diff options
Diffstat (limited to 'src')
76 files changed, 25172 insertions, 0 deletions
diff --git a/src/ildasm/.gitmirrorall b/src/ildasm/.gitmirrorall new file mode 100644 index 0000000000..9ee5c57b99 --- /dev/null +++ b/src/ildasm/.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/ildasm/DynamicArray.h b/src/ildasm/DynamicArray.h new file mode 100644 index 0000000000..eb2aab269f --- /dev/null +++ b/src/ildasm/DynamicArray.h @@ -0,0 +1,110 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef DYNAMICARRAY_H + +#define DYNAMICARRAY_H + +#include "memory.h" + +const int START_SIZE = 24 ; +const int MIN_SIZE = 8 ; + +template <class T> +class DynamicArray +{ + public: + DynamicArray(int iSize = START_SIZE) ; + ~DynamicArray() ; + T& operator[](int i) ; + bool Error() ; + private: + T* m_pArray ; + int m_iMemSize ; + int m_iArraySize ; + bool m_bError ; +}; + +/************************************************************************ + * * + * Default constructor. User has option to pass in the size of the * + * initial array. * + * * + ************************************************************************/ +template<class T> DynamicArray<T>::DynamicArray(int iSize) +{ + if( iSize < MIN_SIZE ) + { + iSize = MIN_SIZE ; + } + m_pArray = new T[iSize] ; + m_iMemSize = iSize ; + m_iArraySize = 0 ; + m_bError = false ; +} + +/************************************************************************ + * * + * Destructor. All it really has to do is delete the array. * + * * + ************************************************************************/ +template<class T> DynamicArray<T>::~DynamicArray() +{ + if( m_pArray ) + { + delete [] m_pArray ; + } +} + +/************************************************************************ + * * + * operator [] to work on the left or right side of the equation. * + * * + ************************************************************************/ +template<class T> T& DynamicArray<T>::operator [](int iIndex) +{ + if( iIndex < 0 ) + { + // Error, set error value to true and return the first element of the array + m_bError = true ; + return m_pArray[0] ; + } + else if ( iIndex >= m_iArraySize ) + { + if( iIndex >= m_iMemSize ) + { + int iNewSize ; + if( iIndex >= m_iMemSize * 2 ) + { + iNewSize = iIndex + 1 ; + } + else + { + iNewSize = m_iMemSize * 2 ; + } + + // We need to allocate more memory + T* pTmp = new T[iNewSize] ; + memcpy(pTmp, m_pArray, m_iMemSize * sizeof(T)) ; + delete [] m_pArray ; + m_pArray = pTmp ; + // Record the new memory size + m_iMemSize = iNewSize ; + } + + //ZeroMemory(&m_pArray[iIndex], sizeof(T)) ; + + ++m_iArraySize ; + } + + return m_pArray[iIndex] ; +} + +template<class T> bool DynamicArray<T>::Error() +{ + return m_bError ; +} + +#endif diff --git a/src/ildasm/Litening.ico b/src/ildasm/Litening.ico Binary files differnew file mode 100644 index 0000000000..7bdaa4f1e9 --- /dev/null +++ b/src/ildasm/Litening.ico diff --git a/src/ildasm/ceeload.cpp b/src/ildasm/ceeload.cpp new file mode 100644 index 0000000000..1c71ecfbd8 --- /dev/null +++ b/src/ildasm/ceeload.cpp @@ -0,0 +1,267 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// CEELOAD reads in the PE file format using LoadLibrary +// =========================================================================== +#include "ildasmpch.h" + +#include "ceeload.h" +#include <corhdr.h> +#include <corimage.h> +#include "util.hpp" +#include "pedecoder.h" + +/*************************************************************************************/ +// Constructor and destructor! +/*************************************************************************************/ +PELoader::PELoader() +{ + m_hFile = NULL; + m_hMod = NULL; + m_hMapFile = NULL; + m_pNT64 = NULL; + m_bIsPE32 = FALSE; + m_FileSize = m_FileSizeAligned = 0; +} + +PELoader::~PELoader() +{ + + m_hMod = NULL; + m_pNT64 = NULL; + // If we have an hFile then we opened this file ourselves! + // If we do not then this file was loaded by the OS and the OS will + // close it for us. + if (m_hFile) + this->close(); +} + +/*************************************************************************************/ +/*************************************************************************************/ +void PELoader::close() +{ + + // _ASSERTE(m_hFile != NULL); + if (m_hFile) + { + if (m_hMod) + UnmapViewOfFile((void*)m_hMod); + if (m_hMapFile) + CloseHandle(m_hMapFile); + CloseHandle(m_hFile); + + m_hMod = NULL; + m_hMapFile = NULL; + m_hFile = NULL; + m_FileSize = m_FileSizeAligned = 0; + } +} + + +BOOL PELoader::open(LPCSTR moduleName) +{ + HMODULE newhMod = NULL; + DWORD dwFileSizeLow; + + _ASSERTE(moduleName); + if (!moduleName) + return FALSE; + + + m_hFile = CreateFileA(moduleName, GENERIC_READ, FILE_SHARE_READ, + 0, OPEN_EXISTING, 0, 0); + if (m_hFile == INVALID_HANDLE_VALUE) + return FALSE; + + dwFileSizeLow = GetFileSize( m_hFile, NULL); + if (dwFileSizeLow == INVALID_FILE_SIZE) + return FALSE; + m_FileSize = dwFileSizeLow; + + m_hMapFile = WszCreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (m_hMapFile == NULL) + return FALSE; + + newhMod = (HMODULE) MapViewOfFile(m_hMapFile, FILE_MAP_READ, 0, 0, 0); + if (newhMod == NULL) + return FALSE; + return open(newhMod); +} + +BOOL PELoader::open(const WCHAR* moduleName) +{ + HMODULE newhMod = NULL; + DWORD dwFileSizeLow; + + _ASSERTE(moduleName); + if (!moduleName) + return FALSE; + + m_hFile = WszCreateFile(moduleName, GENERIC_READ, FILE_SHARE_READ, + 0, OPEN_EXISTING, 0, 0); + if (m_hFile == INVALID_HANDLE_VALUE) + return FALSE; + + dwFileSizeLow = GetFileSize( m_hFile, NULL); + if (dwFileSizeLow == INVALID_FILE_SIZE) + return FALSE; + m_FileSize = dwFileSizeLow; + + m_hMapFile = WszCreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (m_hMapFile == NULL) + return FALSE; + + newhMod = (HMODULE) MapViewOfFile(m_hMapFile, FILE_MAP_READ, 0, 0, 0); + if (newhMod == NULL) + return FALSE; + return open(newhMod); +} + + +/*************************************************************************************/ +BOOL PELoader::open(HMODULE hMod) +{ + IMAGE_DOS_HEADER * pdosHeader; + + // get the dos header... + m_hMod = hMod; + pdosHeader = (IMAGE_DOS_HEADER*) hMod; + // If this is not a PE32+ image + if (pdosHeader->e_magic == VAL16(IMAGE_DOS_SIGNATURE) && + 0 < VAL32(pdosHeader->e_lfanew) && VAL32(pdosHeader->e_lfanew) < 0xFF0) // has to start on first page + { + size_t fileAlignment; + + m_pNT32 = (IMAGE_NT_HEADERS32*) ((BYTE *)m_hMod + VAL32(pdosHeader->e_lfanew)); + + m_bIsPE32 = (m_pNT32->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)); + + if (m_bIsPE32) + { + if ((m_pNT32->Signature != VAL32(IMAGE_NT_SIGNATURE)) || + (m_pNT32->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER32)))) + { + // Make this appear uninitalized because for some reason this file is toasted. + m_pNT32 = NULL; + m_hMod = NULL; + return FALSE; + } + fileAlignment = VAL32(m_pNT32->OptionalHeader.FileAlignment)-1; + } + else //For now assume not i386 is IA64 + { + if ((m_pNT64->Signature != VAL32(IMAGE_NT_SIGNATURE)) || + (m_pNT64->FileHeader.SizeOfOptionalHeader != VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)))) + { + // Make this appear uninitalized because for some reason this file is toasted. + m_pNT64 = NULL; + m_hMod = NULL; + return FALSE; + } + fileAlignment = VAL32(m_pNT64->OptionalHeader.FileAlignment)-1; + } + m_FileSizeAligned = (m_FileSize + fileAlignment)&(~fileAlignment); + } + else + { + // Make this appear uninitalized because for some reason this file is toasted. + m_hMod = NULL; + return FALSE; + } + return TRUE; +} + +/*************************************************************************************/ +void PELoader::dump() +{ +} + +/*************************************************************************************/ +BOOL PELoader::getCOMHeader(IMAGE_COR20_HEADER **ppCorHeader) +{ + PIMAGE_SECTION_HEADER pSectionHeader; + + if (m_bIsPE32) + { + PIMAGE_NT_HEADERS32 pImageHeader; + // Get the image header from the image, then get the directory location + // of the COM+ header which may or may not be filled out. + pImageHeader = (PIMAGE_NT_HEADERS32)Cor_RtlImageNtHeader(m_hMod, (ULONG) m_FileSize); + PREFIX_ASSUME(pImageHeader != NULL); + pSectionHeader = (PIMAGE_SECTION_HEADER) Cor_RtlImageRvaToVa32(pImageHeader, (PBYTE)m_hMod, + VAL32(pImageHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COMHEADER].VirtualAddress), + (DWORD)m_FileSizeAligned /* FileLength */); + } + else + { + PIMAGE_NT_HEADERS64 pImageHeader; + + // Get the image header from the image, then get the directory location + // of the COM+ header which may or may not be filled out. + pImageHeader = (PIMAGE_NT_HEADERS64)Cor_RtlImageNtHeader(m_hMod, (ULONG) m_FileSize); + PREFIX_ASSUME(pImageHeader != NULL); + pSectionHeader = (PIMAGE_SECTION_HEADER) Cor_RtlImageRvaToVa64(pImageHeader, (PBYTE)m_hMod, + VAL32(pImageHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COMHEADER].VirtualAddress), + (DWORD)m_FileSizeAligned /* FileLength */); + } + + // If the section header exists, then return ok and the address. + if (pSectionHeader) + { + *ppCorHeader = (IMAGE_COR20_HEADER *) pSectionHeader; + return TRUE; + } + // If there is no COM+ Data in this image, return false. + else + return FALSE; +} + +/*************************************************************************************/ +BOOL PELoader::getVAforRVA(DWORD rva,void **ppva) +{ + PIMAGE_SECTION_HEADER pSectionHeader; + + if (m_bIsPE32) + { + // Get the image header from the image, then get the directory location + // of the COM+ header which may or may not be filled out. + PIMAGE_NT_HEADERS32 pImageHeader; + pImageHeader = (PIMAGE_NT_HEADERS32) Cor_RtlImageNtHeader(m_hMod, (ULONG) m_FileSize); + PREFIX_ASSUME(pImageHeader != NULL); + pSectionHeader = (PIMAGE_SECTION_HEADER) Cor_RtlImageRvaToVa32(pImageHeader, (PBYTE)m_hMod, + rva, (DWORD)m_FileSizeAligned /* FileLength */); + } + else + { + PIMAGE_NT_HEADERS64 pImageHeader; + pImageHeader = (PIMAGE_NT_HEADERS64) Cor_RtlImageNtHeader(m_hMod, (ULONG) m_FileSize); + PREFIX_ASSUME(pImageHeader != NULL); + pSectionHeader = (PIMAGE_SECTION_HEADER) Cor_RtlImageRvaToVa64(pImageHeader, (PBYTE)m_hMod, + rva, (DWORD)m_FileSizeAligned /* FileLength */); + } + + // If the section header exists, then return ok and the address. + if (pSectionHeader) + { + *ppva = pSectionHeader; + return TRUE; + } + // If there is no COM+ Data in this image, return false. + else + return FALSE; +} + +void SectionInfo::Init(PELoader *pPELoader, IMAGE_DATA_DIRECTORY *dir) +{ + _ASSERTE(dir); + m_dwSectionOffset = VAL32(dir->VirtualAddress); + if (m_dwSectionOffset != 0) + m_pSection = pPELoader->base() + m_dwSectionOffset; + else + m_pSection = 0; + m_dwSectionSize = VAL32(dir->Size); +} + diff --git a/src/ildasm/ceeload.h b/src/ildasm/ceeload.h new file mode 100644 index 0000000000..a6c5d63bea --- /dev/null +++ b/src/ildasm/ceeload.h @@ -0,0 +1,78 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// =========================================================================== +// File: CEELOAD.H +// + +// CEELOAD.H defines the class use to represent the PE file +// =========================================================================== +#ifndef CEELoad_H +#define CEELoad_H + +class PELoader; + +// +// Used to cache information about sections we're interested in (descr, callsig, il) +// +class SectionInfo +{ +public: + BYTE * m_pSection; // pointer to the beginning of the section + DWORD m_dwSectionOffset; // RVA + DWORD m_dwSectionSize; + + // init this class's member variables from the provided directory + void Init(PELoader *pPELoader, IMAGE_DATA_DIRECTORY *dir); + + // returns whether this RVA is inside the section + BOOL InSection(DWORD dwRVA) + { + return (dwRVA >= m_dwSectionOffset) && (dwRVA < m_dwSectionOffset + m_dwSectionSize); + } +}; + +class PELoader { + protected: + + HMODULE m_hMod; + HANDLE m_hFile; + HANDLE m_hMapFile; + BOOL m_bIsPE32; + size_t m_FileSize; + size_t m_FileSizeAligned; + + union + { + PIMAGE_NT_HEADERS64 m_pNT64; + PIMAGE_NT_HEADERS32 m_pNT32; + }; + + public: + SectionInfo m_DescrSection; + SectionInfo m_CallSigSection; + SectionInfo m_ILSection; + + PELoader(); + ~PELoader(); + BOOL open(const char* moduleNameIn); + BOOL open(const WCHAR* moduleNameIn); + BOOL open(HMODULE hMod); + BOOL getCOMHeader(IMAGE_COR20_HEADER **ppCorHeader); + BOOL getVAforRVA(DWORD rva,void **ppCorHeader); + void close(); + void dump(); + inline BOOL IsPE32() { return m_bIsPE32; }; + inline PIMAGE_NT_HEADERS32 ntHeaders32() { return m_pNT32; }; + inline PIMAGE_NT_HEADERS64 ntHeaders64() { return m_pNT64; }; + inline PIMAGE_DOS_HEADER dosHeader() { return (PIMAGE_DOS_HEADER)m_hMod; }; + inline PIMAGE_FILE_HEADER coffHeader() { return &(m_pNT32->FileHeader); }; + inline DWORD Signature() { return m_pNT32->Signature; }; + inline BYTE* base() { return (BYTE*) m_hMod; }; + inline HMODULE getHModule() { return m_hMod; }; + inline HANDLE getHFile() { return m_hFile; } ; +}; + +#endif // CEELoad_H diff --git a/src/ildasm/class.bmp b/src/ildasm/class.bmp Binary files differnew file mode 100644 index 0000000000..1574b641df --- /dev/null +++ b/src/ildasm/class.bmp diff --git a/src/ildasm/classa.bmp b/src/ildasm/classa.bmp Binary files differnew file mode 100644 index 0000000000..d0467c45e3 --- /dev/null +++ b/src/ildasm/classa.bmp diff --git a/src/ildasm/classag.bmp b/src/ildasm/classag.bmp Binary files differnew file mode 100644 index 0000000000..72793ce02f --- /dev/null +++ b/src/ildasm/classag.bmp diff --git a/src/ildasm/classe.bmp b/src/ildasm/classe.bmp Binary files differnew file mode 100644 index 0000000000..a5f641c915 --- /dev/null +++ b/src/ildasm/classe.bmp diff --git a/src/ildasm/classeg.bmp b/src/ildasm/classeg.bmp Binary files differnew file mode 100644 index 0000000000..3aeded1ed2 --- /dev/null +++ b/src/ildasm/classeg.bmp diff --git a/src/ildasm/classi.bmp b/src/ildasm/classi.bmp Binary files differnew file mode 100644 index 0000000000..74d64feb09 --- /dev/null +++ b/src/ildasm/classi.bmp diff --git a/src/ildasm/classig.bmp b/src/ildasm/classig.bmp Binary files differnew file mode 100644 index 0000000000..79b43144a9 --- /dev/null +++ b/src/ildasm/classig.bmp diff --git a/src/ildasm/classv.bmp b/src/ildasm/classv.bmp Binary files differnew file mode 100644 index 0000000000..ecf345ac05 --- /dev/null +++ b/src/ildasm/classv.bmp diff --git a/src/ildasm/classvg.bmp b/src/ildasm/classvg.bmp Binary files differnew file mode 100644 index 0000000000..a77f99b359 --- /dev/null +++ b/src/ildasm/classvg.bmp diff --git a/src/ildasm/dasm.cpp b/src/ildasm/dasm.cpp new file mode 100644 index 0000000000..a9cb52e707 --- /dev/null +++ b/src/ildasm/dasm.cpp @@ -0,0 +1,7870 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "ildasmpch.h" +#include <crtdbg.h> +#include <utilcode.h> +#include "specstrings.h" +#include "debugmacros.h" +#include "corpriv.h" +#include "ceeload.h" +#include "dynamicarray.h" +#include <metamodelpub.h> +#include "formattype.h" + +#define DECLARE_DATA +#include "dasmenum.hpp" +#include "dis.h" + +#include "dasmgui.h" +#include "resource.h" +#include "dasm_sz.h" + +//#define MAX_FILENAME_LENGTH 2048 //moved to dis.h + +#include <corsym.h> +#include <ndpversion.h> + +// Disable the "initialization of static local vars is no thread safe" error +#ifdef _MSC_VER +#pragma warning(disable : 4640) +#endif + +#if defined(_DEBUG) && defined(FEATURE_PREJIT) +#include <corcompile.h> +#endif + +// Define also LegacyActivationShim::CoInitializeEE wrapper around CoInitializeEE +#define LEGACY_ACTIVATION_SHIM_DEFINE_CoInitializeEE +#include "LegacyActivationShim.h" +#include "clrinternal.h" + + + +struct MIDescriptor +{ + mdToken tkClass; // defining class token + mdToken tkDecl; // implemented method token + mdToken tkBody; // implementing method token + mdToken tkBodyParent; // parent of the implementing method +}; + +ISymUnmanagedReader* g_pSymReader = NULL; + +IMDInternalImport* g_pImport = NULL; +IMetaDataImport2* g_pPubImport; +extern IMetaDataAssemblyImport* g_pAssemblyImport; +PELoader * g_pPELoader; +void * g_pMetaData; +unsigned g_cbMetaData; +IMAGE_COR20_HEADER * g_CORHeader; +DynamicArray<__int32> *g_pPtrTags = NULL; //to keep track of all "ldptr" +DynamicArray<DWORD> *g_pPtrSize= NULL; //to keep track of all "ldptr" +int g_iPtrCount = 0; +mdToken * g_cl_list = NULL; +mdToken * g_cl_enclosing = NULL; +BYTE* g_enum_td_type = NULL; // enum (TD) underlying types +BYTE* g_enum_tr_type = NULL; // enum (TR) underlying types +IMDInternalImport** g_asmref_import = NULL; // IMDInternalImports for external assemblies +DynamicArray<MIDescriptor> *g_pmi_list = NULL; +DWORD g_NumMI; +DWORD g_NumClasses; +DWORD g_NumTypeRefs; +DWORD g_NumAsmRefs; +DWORD g_NumModules; +BOOL g_fDumpIL = TRUE; +BOOL g_fDumpHeader = FALSE; +BOOL g_fDumpAsmCode = TRUE; +extern BOOL g_fDumpTokens; // declared in formatType.cpp +BOOL g_fDumpStats = FALSE; +BOOL g_fTDC = TRUE; +BOOL g_fShowCA = TRUE; +BOOL g_fCAVerbal = FALSE; +BOOL g_fShowRefs = FALSE; + +BOOL g_fDumpToPerfWriter = FALSE; +HANDLE g_PerfDataFilePtr = NULL; + +BOOL g_fDumpClassList = FALSE; +BOOL g_fDumpTypeList = FALSE; +BOOL g_fDumpSummary = FALSE; +BOOL g_fDecompile = FALSE; // still in progress +BOOL g_fShowBytes = FALSE; +BOOL g_fShowSource = FALSE; +BOOL g_fPrettyPrint = FALSE; +BOOL g_fInsertSourceLines = FALSE; +BOOL g_fThisIsInstanceMethod; +BOOL g_fTryInCode = TRUE; + +BOOL g_fLimitedVisibility = FALSE; +#if defined(_DEBUG) && defined(FEATURE_PREJIT) +BOOL g_fNGenNativeMetadata = FALSE; +#endif +BOOL g_fHidePub = TRUE; +BOOL g_fHidePriv = TRUE; +BOOL g_fHideFam = TRUE; +BOOL g_fHideAsm = TRUE; +BOOL g_fHideFAA = TRUE; +BOOL g_fHideFOA = TRUE; +BOOL g_fHidePrivScope = TRUE; + +BOOL g_fProject = FALSE; // if .winmd file, transform to .NET view + +extern BOOL g_fQuoteAllNames; // declared in formatType.cpp, init to FALSE +BOOL g_fShowProgressBar = TRUE; +BOOL g_fForwardDecl=FALSE; + +char g_szAsmCodeIndent[MAX_MEMBER_LENGTH]; +char g_szNamespace[MAX_MEMBER_LENGTH]; + +DWORD g_Mode = MODE_DUMP_ALL; + +char g_pszClassToDump[MAX_CLASSNAME_LENGTH]; +char g_pszMethodToDump[MAX_MEMBER_LENGTH]; +char g_pszSigToDump[MAX_SIGNATURE_LENGTH]; + +BOOL g_fCustomInstructionEncodingSystem = FALSE; + +COR_FIELD_OFFSET *g_rFieldOffset = NULL; +ULONG g_cFieldsMax, g_cFieldOffsets; +char g_szInputFile[MAX_FILENAME_LENGTH]; // in UTF-8 +WCHAR g_wszFullInputFile[MAX_PATH + 1]; // in UTF-16 +char g_szOutputFile[MAX_FILENAME_LENGTH]; // in UTF-8 +char* g_pszObjFileName; +FILE* g_pFile = NULL; + +mdToken g_tkClassToDump = 0; +mdToken g_tkMethodToDump = 0; + +unsigned g_uConsoleCP = CP_ACP; +unsigned g_uCodePage = g_uConsoleCP; + +char* g_rchCA = NULL; // dyn.allocated array of CA dumped/not flags +unsigned g_uNCA = 0; // num. of CAs + +struct ResourceNode; +extern DynamicArray<LocalComTypeDescr*> *g_pLocalComType; +extern ULONG g_LocalComTypeNum; + +// MetaInfo integration: +#include "../tools/metainfo/mdinfo.h" +#include "ivehandler.h" +BOOL g_fDumpMetaInfo = FALSE; +ULONG g_ulMetaInfoFilter = MDInfo::dumpDefault; +// Validator module type. +DWORD g_ValModuleType = ValidatorModuleTypeInvalid; +IMetaDataDispenserEx *g_pDisp = NULL; +void DisplayFile(__in __nullterminated wchar_t* szFile, + BOOL isFile, + ULONG DumpFilter, + __in_opt __nullterminated wchar_t* szObjFile, + strPassBackFn pDisplayString); +extern mdMethodDef g_tkEntryPoint; // integration with MetaInfo +// Abort disassembly flag: +BOOL g_fAbortDisassembly = FALSE; + +DWORD DumpResourceToFile(__in __nullterminated WCHAR* wzFileName); // see DRES.CPP + +struct VTableRef +{ + mdMethodDef tkTok; + WORD wEntry; + WORD wSlot; +}; + +DynamicArray<VTableRef> *g_prVTableRef = NULL; +ULONG g_nVTableRef = 0; + +struct EATableRef +{ + mdMethodDef tkTok; + char* pszName; +}; +DynamicArray<EATableRef> *g_prEATableRef=NULL; +ULONG g_nEATableRef = 0; +ULONG g_nEATableBase = 0; + +extern HINSTANCE g_hResources; +void DumpCustomAttributeProps(mdToken tkCA, mdToken tkType, mdToken tkOwner, BYTE*pBlob, ULONG ulLen, void *GUICookie, bool bWithOwner); + +WCHAR* RstrW(unsigned id) +{ + static WCHAR buffer[1024]; + DWORD cchBuff = (DWORD)COUNTOF(buffer); + WCHAR* buff = (WCHAR*)buffer; + memset(buffer,0,sizeof(buffer)); + switch(id) + { + case IDS_E_DASMOK: + case IDS_E_PARTDASM: + case IDS_E_PARAMSEQNO: + case IDS_E_MEMBRENUM: + case IDS_E_ODDMEMBER: + case IDS_E_ENUMINIT: + case IDS_E_NODATA: + case IDS_E_VTFUTABLE: + case IDS_E_BOGUSRVA: + case IDS_E_EATJTABLE: + case IDS_E_EATJSIZE: + case IDS_E_RESFLAGS: + case IDS_E_MIHENTRY: + case IDS_E_CODEMGRTBL: + case IDS_E_COMIMAGE: + case IDS_E_MDDETAILS: + case IDS_E_MISTART: + case IDS_E_MIEND: + case IDS_E_ONLYITEMS: + case IDS_E_DECOMPRESS: + case IDS_E_COMPRESSED: + case IDS_E_INSTRDECOD: + case IDS_E_INSTRTYPE: + case IDS_E_SECTHEADER: + case IDS_E_MDAIMPORT: + case IDS_E_MDAFROMMDI: + case IDS_E_MDIIMPORT: + case IDS_E_NOMANIFEST: + case IDS_W_CREATEDW32RES: + case IDS_E_CORRUPTW32RES: + case IDS_E_CANTACCESSW32RES: + case IDS_E_CANTOPENW32RES: + case IDS_ERRORREOPENINGFILE: + wcscpy_s(buffer,COUNTOF(buffer),L"// "); + buff +=3; + cchBuff -= 3; + break; + case IDS_E_AUTOCA: + case IDS_E_METHBEG: + case IDS_E_DASMNATIVE: + case IDS_E_METHODRT: + case IDS_E_CODESIZE: + case IDS_W_CREATEDMRES: + case IDS_E_READINGMRES: + wcscpy_s(buffer,COUNTOF(buffer),L"%s// "); + buff +=5; + cchBuff -= 5; + break; + case IDS_E_NORVA: + wcscpy_s(buffer,COUNTOF(buffer),L"/* "); + buff += 3; + cchBuff -= 3; + break; + default: + break; + } + _ASSERTE(g_hResources != NULL); + WszLoadString(g_hResources,id,buff,cchBuff); + if(id == IDS_E_NORVA) + wcscat_s(buff,cchBuff,L" */"); + return buffer; +} +char* RstrA(unsigned n, unsigned codepage) +{ + static char buff[2048]; + WCHAR* wz = RstrW(n); + // Unicode -> UTF-8 + memset(buff,0,sizeof(buff)); + if(!WszWideCharToMultiByte(codepage,0,(LPCWSTR)wz,-1,buff,sizeof(buff),NULL,NULL)) + buff[0] = 0; + return buff; +} +char* RstrUTF(unsigned n) +{ + return RstrA(n,CP_UTF8); +} + +char* RstrANSI(unsigned n) +{ + return RstrA(n,g_uConsoleCP); +} + +#if 0 +void PrintEncodingSystem() +{ + long i; + + printf("Custom opcode encoding system employed\n"); + printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + + for (i = 0; i < 256; i++) + { + long value = g_pInstructionDecodingTable->m_SingleByteOpcodes[i]; + + printf("0x%02x --> ", i); + printf("%s\n", OpcodeInfo[value].pszName); + } +} +#endif + +// buffers for formatType functions +extern CQuickBytes * g_szBuf_KEYWORD; +extern CQuickBytes * g_szBuf_COMMENT; +extern CQuickBytes * g_szBuf_ERRORMSG; +extern CQuickBytes * g_szBuf_ANCHORPT; +extern CQuickBytes * g_szBuf_JUMPPT; +extern CQuickBytes * g_szBuf_UnquotedProperName; +extern CQuickBytes * g_szBuf_ProperName; + +// CLR internal hosting API +ICLRRuntimeHostInternal *g_pCLRRuntimeHostInternal = NULL; + +BOOL Init() +{ + if (FAILED(CoInitialize(NULL))) + { + return FALSE; + } + + if (FAILED(LegacyActivationShim::CoInitializeCor(COINITCOR_DEFAULT))) + { + return FALSE; + } + + if (FAILED(LegacyActivationShim::CoInitializeEE(COINITEE_DEFAULT))) + { + return FALSE; + } + + ICLRRuntimeInfo *pCLRRuntimeInfo = NULL; + if (FAILED(LegacyActivationShim::Util::GetCLRRuntimeInfo(&pCLRRuntimeInfo))) + { + return FALSE; + } + + if (FAILED(pCLRRuntimeInfo->GetInterface( + CLSID_CLRRuntimeHostInternal, + IID_ICLRRuntimeHostInternal, + (LPVOID *)&g_pCLRRuntimeHostInternal))) + { + return FALSE; + } + + g_szBuf_KEYWORD = new CQuickBytes(); + g_szBuf_COMMENT = new CQuickBytes(); + g_szBuf_ERRORMSG = new CQuickBytes(); + g_szBuf_ANCHORPT = new CQuickBytes(); + g_szBuf_JUMPPT = new CQuickBytes(); + g_szBuf_UnquotedProperName = new CQuickBytes(); + g_szBuf_ProperName = new CQuickBytes(); + return TRUE; +} // Init + +extern LPCSTR *rAsmRefName; // decl. in formatType.cpp -- for AsmRef aliases +extern ULONG ulNumAsmRefs; // decl. in formatType.cpp -- for AsmRef aliases + +void Cleanup() +{ + if (g_pAssemblyImport != NULL) + { + g_pAssemblyImport->Release(); + g_pAssemblyImport = NULL; + } + if (g_pPubImport != NULL) + { + g_pPubImport->Release(); + g_pPubImport = NULL; + } + if (g_pImport != NULL) + { + g_pImport->Release(); + g_pImport = NULL; + TokenSigDelete(); + } + if (g_pDisp != NULL) + { + g_pDisp->Release(); + g_pDisp = NULL; + } + + if (g_pSymReader != NULL) + { + g_pSymReader->Release(); + g_pSymReader = NULL; + } + if (g_pPELoader != NULL) + { + g_pPELoader->close(); + SDELETE(g_pPELoader); + } + g_iPtrCount = 0; + g_NumClasses = 0; + g_NumTypeRefs = 0; + g_NumModules = 0; + g_tkEntryPoint = 0; + g_szAsmCodeIndent[0] = 0; + g_szNamespace[0]=0; + g_pszClassToDump[0]=0; + g_pszMethodToDump[0]=0; + g_pszSigToDump[0] = 0; + g_NumDups = 0; + g_NumRefs = 0; + g_NumMI = 0; + g_LocalComTypeNum = 0; + g_nEATableRef = 0; + + g_fCustomInstructionEncodingSystem = FALSE; + + if (rAsmRefName != NULL) + { + for (int i = 0; (unsigned)i < ulNumAsmRefs; i++) + { + if (rAsmRefName[i] != NULL) VDELETE(rAsmRefName[i]); + } + VDELETE(rAsmRefName); + ulNumAsmRefs = 0; + } + + if (g_rchCA != NULL) + VDELETE(g_rchCA); + + if (g_cl_list != NULL) VDELETE(g_cl_list); + if (g_cl_enclosing != NULL) VDELETE(g_cl_enclosing); + if (g_pmi_list != NULL) SDELETE(g_pmi_list); + if (g_dups != NULL) SDELETE(g_dups); + if (g_enum_td_type != NULL) VDELETE(g_enum_td_type); + if (g_enum_tr_type != NULL) VDELETE(g_enum_tr_type); + if (g_asmref_import != NULL) + { + for (DWORD i = 0; i < g_NumAsmRefs; i++) + { + if (g_asmref_import[i] != NULL) + g_asmref_import[i]->Release(); + } + VDELETE(g_asmref_import); + g_NumAsmRefs = 0; + } +} // Cleanup + +void Uninit() +{ + GUIAddOpcode(NULL,NULL); + + if (g_pPtrTags != NULL) + { + SDELETE(g_pPtrTags); + } + if (g_pPtrSize != NULL) + { + SDELETE(g_pPtrSize); + } + if (g_pmi_list != NULL) + { + SDELETE(g_pmi_list); + } + if (g_dups != NULL) SDELETE(g_dups); + if (g_refs != NULL) SDELETE(g_refs); + if (g_pLocalComType != NULL) + { + SDELETE(g_pLocalComType); + } + if (g_prVTableRef != NULL) + { + SDELETE(g_prVTableRef); + } + if (g_prEATableRef != NULL) + { + SDELETE(g_prEATableRef); + } + if (g_szBuf_KEYWORD != NULL) + { + SDELETE(g_szBuf_KEYWORD); + } + if (g_szBuf_COMMENT != NULL) + { + SDELETE(g_szBuf_COMMENT); + } + if (g_szBuf_ERRORMSG != NULL) + { + SDELETE(g_szBuf_ERRORMSG); + } + if (g_szBuf_ANCHORPT != NULL) + { + SDELETE(g_szBuf_ANCHORPT); + } + if (g_szBuf_JUMPPT != NULL) + { + SDELETE(g_szBuf_JUMPPT); + } + if (g_szBuf_UnquotedProperName != NULL) + { + SDELETE(g_szBuf_UnquotedProperName); + } + if (g_szBuf_UnquotedProperName != NULL) + { + SDELETE(g_szBuf_ProperName); + } + + if (g_pCLRRuntimeHostInternal != NULL) + { + g_pCLRRuntimeHostInternal->Release(); + g_pCLRRuntimeHostInternal = NULL; + } + + LegacyActivationShim::CoUninitializeEE(COUNINITEE_DEFAULT); + LegacyActivationShim::CoUninitializeCor(); + CoUninitialize(); +} // Uninit + +HRESULT IsClassRefInScope(mdTypeRef classref) +{ + HRESULT hr = S_OK; + const char *pszNameSpace; + const char *pszClassName; + mdTypeDef classdef; + mdToken tkRes; + + IfFailRet(g_pImport->GetNameOfTypeRef(classref, &pszNameSpace, &pszClassName)); + MAKE_NAME_IF_NONE(pszClassName,classref); + IfFailRet(g_pImport->GetResolutionScopeOfTypeRef(classref, &tkRes)); + + hr = g_pImport->FindTypeDef(pszNameSpace, pszClassName, + (TypeFromToken(tkRes) == mdtTypeRef) ? tkRes : mdTokenNil, &classdef); + + return hr; +} + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +BOOL EnumClasses() +{ + HRESULT hr; + HENUMInternal hEnum; + ULONG i = 0,j; + //char szString[1024]; + HENUMInternal hBody; + HENUMInternal hDecl; + + if(g_cl_list) VDELETE(g_cl_list); + if(g_cl_enclosing) VDELETE(g_cl_enclosing); + if (g_pmi_list) SDELETE(g_pmi_list); + if (g_dups) SDELETE(g_dups); + if (g_enum_td_type) VDELETE(g_enum_td_type); + if (g_enum_tr_type) VDELETE(g_enum_tr_type); + if (g_asmref_import) + { + for (DWORD nIndex = 0; nIndex < g_NumAsmRefs; nIndex++) + { + if (g_asmref_import[nIndex] != NULL) + g_asmref_import[nIndex]->Release(); + } + VDELETE(g_asmref_import); + g_NumAsmRefs = 0; + } + //-------------------------------------------------------------- + if (FAILED(g_pImport->EnumAllInit(mdtTypeRef,&hEnum))) + { + printError(g_pFile, "MetaData error: cannot enumerate all TypeRefs"); + return FALSE; + } + g_NumTypeRefs = g_pImport->EnumGetCount(&hEnum); + g_pImport->EnumClose(&hEnum); + + if(g_NumTypeRefs) + { + g_enum_tr_type = new BYTE[g_NumTypeRefs+1]; + if(g_enum_tr_type == NULL) return FALSE; + memset(g_enum_tr_type,0xFF,g_NumTypeRefs+1); + } + //-------------------------------------------------------------- + if (FAILED(g_pImport->EnumAllInit(mdtAssemblyRef, &hEnum))) + { + printError(g_pFile, "MetaData error: cannot enumerate all AssemblyRefs"); + return FALSE; + } + g_NumAsmRefs = g_pImport->EnumGetCount(&hEnum); + g_pImport->EnumClose(&hEnum); + if(g_NumAsmRefs) + { + g_asmref_import = new IMDInternalImport*[g_NumAsmRefs+1]; + if(g_asmref_import == NULL) return FALSE; + memset(g_asmref_import,0,(g_NumAsmRefs+1)*sizeof(IMDInternalImport*)); + } + //-------------------------------------------------------------- + hr = g_pImport->EnumTypeDefInit( + &hEnum); + if (FAILED(hr)) + { + printError(g_pFile,RstrUTF(IDS_E_CLSENUM)); + return FALSE; + } + + g_NumClasses = g_pImport->EnumTypeDefGetCount(&hEnum); + + g_tkClassToDump = 0; + + g_NumMI = 0; + g_NumDups = 0; + + if(g_NumClasses == 0) return TRUE; + + g_enum_td_type = new BYTE[g_NumClasses+1]; + if(g_enum_td_type == NULL) return FALSE; + memset(g_enum_td_type,0xFF,g_NumClasses+1); + + g_cl_list = new mdToken[g_NumClasses]; + if(g_cl_list == NULL) return FALSE; + + g_cl_enclosing = new mdToken[g_NumClasses]; + if(g_cl_enclosing == NULL) + { + VDELETE(g_cl_list); + return FALSE; + } + + g_pmi_list = new DynamicArray<MIDescriptor>; + if(g_pmi_list == NULL) + { + VDELETE(g_cl_enclosing); + VDELETE(g_cl_list); + return FALSE; + } + + g_dups = new DynamicArray<mdToken>; + if(g_dups == NULL) + { + SDELETE(g_pmi_list); + VDELETE(g_cl_enclosing); + VDELETE(g_cl_list); + return FALSE; + } + + // fill the list of typedef tokens + while(g_pImport->EnumTypeDefNext(&hEnum, &g_cl_list[i])) + { + mdToken tkEnclosing; + + if (g_Mode == MODE_DUMP_CLASS || g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + CQuickBytes out; + + // we want plain class name without token values + BOOL fDumpTokens = g_fDumpTokens; + g_fDumpTokens = FALSE; + + WIN_PAL_CPP_TRY + { + if (strcmp(PrettyPrintClass(&out, g_cl_list[i], g_pImport), g_pszClassToDump) == 0) + { + g_tkClassToDump = g_cl_list[i]; + } + } + WIN_PAL_CPP_CATCH_ALL + { } + WIN_PAL_CPP_ENDTRY; + + g_fDumpTokens = fDumpTokens; + } + g_cl_enclosing[i] = mdTypeDefNil; + + hr = g_pImport->GetNestedClassProps(g_cl_list[i],&tkEnclosing); + if (SUCCEEDED(hr) && RidFromToken(tkEnclosing)) // No need to check token validity here, it's done later + g_cl_enclosing[i] = tkEnclosing; + if (SUCCEEDED(g_pImport->EnumMethodImplInit(g_cl_list[i],&hBody,&hDecl))) + { + if ((j = g_pImport->EnumMethodImplGetCount(&hBody,&hDecl))) + { + mdToken tkBody,tkDecl,tkBodyParent; + for (ULONG k = 0; k < j; k++) + { + if (g_pImport->EnumMethodImplNext(&hBody,&hDecl,&tkBody,&tkDecl) == S_OK) + { + if (SUCCEEDED(g_pImport->GetParentToken(tkBody,&tkBodyParent))) + { + (*g_pmi_list)[g_NumMI].tkClass = g_cl_list[i]; + (*g_pmi_list)[g_NumMI].tkBody = tkBody; + (*g_pmi_list)[g_NumMI].tkDecl = tkDecl; + (*g_pmi_list)[g_NumMI].tkBodyParent = tkBodyParent; + g_NumMI++; + } + } + } + } + g_pImport->EnumMethodImplClose(&hBody,&hDecl); + } + i++; + } + g_pImport->EnumTypeDefClose(&hEnum); + // check nesting consistency (circular nesting, invalid enclosers) + for(i = 0; i < g_NumClasses; i++) + { + mdToken tkThis = g_cl_list[i]; + mdToken tkEncloser = g_cl_enclosing[i]; + mdToken tkPrevLevel = tkThis; + while(tkEncloser != mdTypeDefNil) + { + if(tkThis == tkEncloser) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_SELFNSTD),tkThis); + printError(g_pFile,szString); + g_cl_enclosing[i] = mdTypeDefNil; + break; + } + else + { + for(j = 0; (j < g_NumClasses)&&(tkEncloser != g_cl_list[j]); j++); + if(j == g_NumClasses) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_NOENCLOS), + tkPrevLevel,tkEncloser); + printError(g_pFile,szString); + g_cl_enclosing[i] = mdTypeDefNil; + break; + } + else + { + tkPrevLevel = tkEncloser; + tkEncloser = g_cl_enclosing[j]; + } + } + } // end while(tkEncloser != mdTypeDefNil) + } // end for(i = 0; i < g_NumClasses; i++) + + // register all class dups + const char *pszClassName; + const char *pszNamespace; + const char *pszClassName1; + const char *pszNamespace1; + + if (FAILED(g_pImport->GetNameOfTypeDef( + g_cl_list[0], + &pszClassName, + &pszNamespace))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), g_cl_list[0]); + printLine(g_pFile, sz); + return FALSE; + } + if((g_cl_enclosing[0]==mdTypeDefNil) + &&(0==strcmp(pszClassName,"<Module>")) + &&(*pszNamespace == 0)) + { + (*g_dups)[g_NumDups++] = g_cl_list[0]; + } + for(i = 1; i < g_NumClasses; i++) + { + if (FAILED(g_pImport->GetNameOfTypeDef( + g_cl_list[i], + &pszClassName, + &pszNamespace))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), g_cl_list[i]); + printLine(g_pFile, sz); + return FALSE; + } + + for(j = 0; j < i; j++) + { + if (FAILED(g_pImport->GetNameOfTypeDef( + g_cl_list[j], + &pszClassName1, + &pszNamespace1))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), g_cl_list[j]); + printLine(g_pFile, sz); + return FALSE; + } + + if((g_cl_enclosing[i]==g_cl_enclosing[j]) + &&(0==strcmp(pszClassName,pszClassName1)) + &&(0==strcmp(pszNamespace,pszNamespace1))) + { + (*g_dups)[g_NumDups++] = g_cl_list[i]; + break; + } + } + } // end for(i = 1; i < g_NumClasses; i++) + + //register all field and method dups + for(i = 0; i <= g_NumClasses; i++) + { + HENUMInternal hEnumMember; + mdToken *pMemberList = NULL; + DWORD NumMembers,k; + + // methods + if (i != 0) + { + hr = g_pImport->EnumInit(mdtMethodDef, g_cl_list[i-1], &hEnumMember); + } + else + { + hr = g_pImport->EnumGlobalFunctionsInit(&hEnumMember); + } + if (FAILED(hr)) + { + printLine(g_pFile,RstrUTF(IDS_E_MEMBRENUM)); + return FALSE; + } + NumMembers = g_pImport->EnumGetCount(&hEnumMember); + pMemberList = new mdToken[NumMembers]; + for (j = 0; g_pImport->EnumNext(&hEnumMember, &pMemberList[j]); j++); + _ASSERTE(j == NumMembers); + g_pImport->EnumClose(&hEnumMember); + for (j = 1; j < NumMembers; j++) + { + const char *pszName; + ULONG cSig; + PCCOR_SIGNATURE pSig; + if (FAILED(g_pImport->GetNameOfMethodDef(pMemberList[j], &pszName)) || + FAILED(g_pImport->GetSigOfMethodDef(pMemberList[j], &cSig, &pSig))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), pMemberList[j]); + printLine(g_pFile, sz); + return FALSE; + } + for (k = 0; k < j; k++) + { + const char *szName1; + if (FAILED(g_pImport->GetNameOfMethodDef(pMemberList[k], &szName1))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), pMemberList[k]); + printLine(g_pFile, sz); + return FALSE; + } + if (strcmp(pszName, szName1) == 0) + { + ULONG cSig1; + PCCOR_SIGNATURE pSig1; + if (FAILED(g_pImport->GetSigOfMethodDef(pMemberList[k], &cSig1, &pSig1))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), pMemberList[k]); + printLine(g_pFile, sz); + return FALSE; + } + if((cSig == cSig1)&&(0==memcmp(pSig,pSig1,cSig))) + { + (*g_dups)[g_NumDups++] = pMemberList[j]; + break; + } + } + } + } + VDELETE(pMemberList); + + // fields + if (i != 0) + { + hr = g_pImport->EnumInit(mdtFieldDef, g_cl_list[i-1], &hEnumMember); + } + else + { + hr = g_pImport->EnumGlobalFieldsInit(&hEnumMember); + } + if (FAILED(hr)) + { + printLine(g_pFile,RstrUTF(IDS_E_MEMBRENUM)); + return FALSE; + } + NumMembers = g_pImport->EnumGetCount(&hEnumMember); + pMemberList = new mdToken[NumMembers]; + for (j = 0; g_pImport->EnumNext(&hEnumMember, &pMemberList[j]); j++); + _ASSERTE(j == NumMembers); + g_pImport->EnumClose(&hEnumMember); + for (j = 1; j < NumMembers; j++) + { + const char *pszName; + ULONG cSig; + PCCOR_SIGNATURE pSig; + if (FAILED(g_pImport->GetNameOfFieldDef(pMemberList[j], &pszName)) || + FAILED(g_pImport->GetSigOfFieldDef(pMemberList[j], &cSig, &pSig))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), pMemberList[j]); + printLine(g_pFile, sz); + return FALSE; + } + for (k = 0; k < j; k++) + { + const char *szName1; + if (FAILED(g_pImport->GetNameOfFieldDef(pMemberList[k], &szName1))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), pMemberList[k]); + printLine(g_pFile, sz); + return FALSE; + } + if (strcmp(pszName, szName1) == 0) + { + ULONG cSig1; + PCCOR_SIGNATURE pSig1; + if (FAILED(g_pImport->GetSigOfFieldDef(pMemberList[k], &cSig1, &pSig1))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), pMemberList[k]); + printLine(g_pFile, sz); + return FALSE; + } + if((cSig == cSig1)&&(0==memcmp(pSig,pSig1,cSig))) + { + (*g_dups)[g_NumDups++] = pMemberList[j]; + break; + } + } + } + } + VDELETE(pMemberList); + + } // end for(i = 0; i <= g_NumClasses; i++) + return TRUE; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +#ifndef _DEBUG +bool HasSuppressingAttribute() +{ + const void* pData; + ULONG cbData; + + return ((S_OK == g_pImport->GetCustomAttributeByName(TokenFromRid(mdtModule,1), + (LPCUTF8)"System.Runtime.CompilerServices.SuppressIldasmAttribute", + &pData, + &cbData)) + || (S_OK == g_pImport->GetCustomAttributeByName(TokenFromRid(mdtAssembly,1), + (LPCUTF8)"System.Runtime.CompilerServices.SuppressIldasmAttribute", + &pData, + &cbData))); +} +#endif +void DumpMscorlib(void* GUICookie) +{ + if(g_pAssemblyImport==NULL) g_pAssemblyImport = GetAssemblyImport(GUICookie); + if(g_pAssemblyImport!=NULL) + { + mdAssembly tkAsm; + if(SUCCEEDED(g_pAssemblyImport->GetAssemblyFromScope(&tkAsm))&&(tkAsm != mdAssemblyNil)) + { + const void* pPublicKey; + ULONG cbPublicKey = 0; + ULONG ulHashAlgId; + WCHAR wzName[1024]; + ULONG ulNameLen=0; + ASSEMBLYMETADATA md; + WCHAR wzLocale[1024]; + DWORD dwFlags; + //char szString[4096]; + + md.szLocale = wzLocale; + md.cbLocale = 1024; + md.rProcessor = NULL; + md.ulProcessor = 0; + md.rOS = NULL; + md.ulOS = 0; + + if(SUCCEEDED(g_pAssemblyImport->GetAssemblyProps( // S_OK or error. + tkAsm, // [IN] The Assembly for which to get the properties. + &pPublicKey, // [OUT] Pointer to the public key. + &cbPublicKey,// [OUT] Count of bytes in the public key. + &ulHashAlgId,// [OUT] Hash Algorithm. + wzName, // [OUT] Buffer to fill with name. + 1024, // [IN] Size of buffer in wide chars. + &ulNameLen, // [OUT] Actual # of wide chars in name. + &md, // [OUT] Assembly MetaData. + &dwFlags))) // [OUT] Flags. + { + if(wcscmp(wzName,L"mscorlib") == 0) + { + printLine(GUICookie,""); + sprintf_s(szString,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".mscorlib")); + printLine(GUICookie,szString); + printLine(GUICookie,""); + } + } + } + } +} +void DumpTypelist(void* GUICookie) +{ + if(g_NumClasses > 1) + { + DWORD i; + CQuickBytes out; + printLine(GUICookie,""); + sprintf_s(szString,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".typelist")); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + + for(i = 0; i < g_NumClasses; i++) + { + out.Shrink(0); + sprintf_s(szString,SZSTRING_SIZE, "%s%s",g_szAsmCodeIndent, PrettyPrintClass(&out, g_cl_list[i], g_pImport)); + printLine(GUICookie,szString); + } + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); + printLine(GUICookie,""); + } + +} +#define ELEMENT_TYPE_TYPEDEF ELEMENT_TYPE_MAX+1 +BOOL EnumTypedefs() +{ + HENUMInternal hEnum; + ULONG i,l; + mdToken tk; + if (g_typedefs) SDELETE(g_typedefs); + g_typedefs = new DynamicArray<TypeDefDescr>; + g_NumTypedefs = 0; + if (FAILED(g_pImport->EnumAllInit(mdtTypeSpec, &hEnum))) + { + return FALSE; + } + for (i = 0; g_pImport->EnumNext(&hEnum, &tk); i++) + { + ULONG cSig; + PCCOR_SIGNATURE sig; + if (FAILED(g_pImport->GetSigFromToken(tk, &cSig, &sig))) + { + return FALSE; + } + if (*sig == ELEMENT_TYPE_TYPEDEF) + { + TypeDefDescr* pTDD = &((*g_typedefs)[g_NumTypedefs]); + pTDD->szName = (char*)sig+1; + l = 2+(ULONG)strlen((char*)sig+1); + pTDD->tkTypeSpec = GET_UNALIGNED_VAL32(sig + l); + pTDD->tkSelf = tk; + if (TypeFromToken(pTDD->tkTypeSpec) == mdtTypeSpec) + { + if (FAILED(g_pImport->GetSigFromToken(pTDD->tkTypeSpec,&(pTDD->cb), &(pTDD->psig)))) + { + return FALSE; + } + } + else if (TypeFromToken(pTDD->tkTypeSpec) == mdtCustomAttribute) + { + l += sizeof(mdToken); + pTDD->psig = sig + l; + pTDD->cb = cSig - l; + } + else + { + pTDD->psig = NULL; + pTDD->cb = 0; + } + g_NumTypedefs++; + } + } + g_pImport->EnumClose(&hEnum); + return TRUE; +} + +void DumpTypedefs(void* GUICookie) +{ + HRESULT hr; + DWORD i; + char* szptr; + CQuickBytes out; + printLine(GUICookie,""); + for(i = 0; i < g_NumTypedefs; i++) + { + TypeDefDescr* pTDD = &((*g_typedefs)[i]); + szptr = &szString[0]; + szString[0] = 0; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,ANCHORPT(KEYWORD(".typedef"),pTDD->tkSelf)); + if(g_fDumpTokens) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),pTDD->tkSelf); + + { + ULONG n = g_NumTypedefs; + DWORD tk = pTDD->tkTypeSpec; + switch (TypeFromToken(tk)) + { + default: + break; + + case mdtCustomAttribute: + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + { + mdToken tkType; + mdToken tkOwner; + BYTE* pBlob=NULL; + ULONG uLen=0; + tkType = GET_UNALIGNED_VAL32(pTDD->psig); + tkOwner = GET_UNALIGNED_VAL32(pTDD->psig + sizeof(mdToken)); + if(pTDD->cb > 2*sizeof(mdToken)) + { + pBlob = (BYTE*)pTDD->psig + 2*sizeof(mdToken); + uLen = pTDD->cb - 2*sizeof(mdToken); + } + DumpCustomAttributeProps(0,tkType,tkOwner,pBlob,uLen,GUICookie, + (RidFromToken(tkOwner)!=0)); + + } + sprintf_s(szString,SZSTRING_SIZE,"%s %s %s", g_szAsmCodeIndent,KEYWORD("as"), + ProperName((*g_typedefs)[i].szName)); + printLine(GUICookie,szString); + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-8]=0; + continue; + + case mdtMethodDef: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("method ")); + break; + + case mdtFieldDef: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("field ")); + break; + + case mdtMemberRef: + { + PCCOR_SIGNATURE typePtr; + const char *pszMemberName; + ULONG cComSig; + + if (FAILED(g_pImport->GetNameAndSigOfMemberRef( + tk, + &typePtr, + &cComSig, + &pszMemberName))) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"ERROR "); + break; + } + unsigned callConv = CorSigUncompressData(typePtr); + + if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD)) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("field ")); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("method ")); + break; + } + } + g_NumTypedefs = 0; + PrettyPrintToken(szString, tk, g_pImport,g_pFile,0); + g_NumTypedefs = n; + szptr = &szString[strlen(szString)]; + } + szptr+= sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %s %s", KEYWORD("as"), ProperName((*g_typedefs)[i].szName)); + printLine(GUICookie,szString); + } +} + +BOOL PrintClassList() +{ + DWORD i; + BOOL fSuccess = FALSE; + //char szString[1024]; + char* szptr; + + if(g_NumClasses) + { + printLine(g_pFile,COMMENT("// Classes defined in this module:")); + printLine(g_pFile,COMMENT("//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")); + + for (i = 0; i < g_NumClasses; i++) + { + const char *pszClassName; + const char *pszNamespace; + DWORD dwClassAttrs; + mdTypeRef crExtends; + + if (FAILED(g_pImport->GetNameOfTypeDef( + g_cl_list[i], + &pszClassName, + &pszNamespace))) + { + printLine(g_pFile, COMMENT("// Invalid TypeDef record")); + return FALSE; + } + MAKE_NAME_IF_NONE(pszClassName,g_cl_list[i]); + // if this is the "<Module>" class (there is a misnomer) then skip it! + if (FAILED(g_pImport->GetTypeDefProps( + g_cl_list[i], + &dwClassAttrs, + &crExtends))) + { + printLine(g_pFile, COMMENT("// Invalid TypeDef record")); + return FALSE; + } + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"// "); + if (IsTdInterface(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"Interface "); + //else if (IsTdValueType(dwClassAttrs)) szptr+=sprintf(szptr,"Value Class"); + //else if (IsTdUnmanagedValueType(dwClassAttrs)) szptr+=sprintf(szptr,"NotInGCHeap Value Class"); + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"Class "); + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%-30s ", pszClassName); + + if (IsTdPublic(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(public) "); + if (IsTdAbstract(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(abstract) "); + if (IsTdAutoLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(auto) "); + if (IsTdSequentialLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(sequential) "); + if (IsTdExplicitLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(explicit) "); + if (IsTdAnsiClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(ansi) "); + if (IsTdUnicodeClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(unicode) "); + if (IsTdAutoClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(autochar) "); + if (IsTdImport(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(import) "); + if (IsTdWindowsRuntime(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(windowsruntime) "); + //if (IsTdEnum(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(enum) "); + if (IsTdSealed(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(sealed) "); + if (IsTdNestedPublic(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(nested public) "); + if (IsTdNestedPrivate(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(nested private) "); + if (IsTdNestedFamily(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(nested family) "); + if (IsTdNestedAssembly(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(nested assembly) "); + if (IsTdNestedFamANDAssem(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(nested famANDassem) "); + if (IsTdNestedFamORAssem(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(nested famORassem) "); + + printLine(g_pFile,COMMENT(szString)); + } + printLine(g_pFile,COMMENT("//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")); + printLine(g_pFile,""); + } + else + printLine(g_pFile,COMMENT("// No classes defined in this module")); + fSuccess = TRUE; + + return fSuccess; +} + +BOOL ValidateToken(mdToken tk, ULONG type = (ULONG) ~0) +{ + BOOL bRtn; + //char szString[1024]; + bRtn = g_pImport->IsValidToken(tk); + if (!bRtn) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_INVALIDTK), tk); + printError(g_pFile,szString); + } + else if (type != (ULONG) ~0 && TypeFromToken(tk) != type) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_UNEXPTYPE), + TypeFromToken(type), TypeFromToken(tk)); + printError(g_pFile,szString); + bRtn = FALSE; + } + return bRtn; +} + + +BOOL DumpModule(mdModuleRef mdMod) +{ + const char *pszModName; + //char szString[1024]; + if (FAILED(g_pImport->GetModuleRefProps(mdMod,&pszModName))) + { + pszModName = "Invalid ModuleRef record"; + } + MAKE_NAME_IF_NONE(pszModName,mdMod); + sprintf_s(szString,SZSTRING_SIZE,"%s%s \"%s\"",g_szAsmCodeIndent,KEYWORD(".import"),pszModName); // what about GUID and MVID? + printLine(g_pFile,szString); + return TRUE; +} + +char* DumpPinvokeMap(DWORD dwMappingFlags, const char *szImportName, + mdModuleRef mrImportDLL, __inout __nullterminated char* szString, void* GUICookie) +{ + const char *szImportDLLName; + char* szptr = &szString[strlen(szString)]; + + if (FAILED(g_pImport->GetModuleRefProps(mrImportDLL,&szImportDLLName))) + { + szImportDLLName = "Invalid ModuleRef record"; + } + if(strlen(szImportDLLName) != 0) + { + szptr = DumpQString(GUICookie, + (char*)szImportDLLName, + g_szAsmCodeIndent, + 80); + } + + //if(strlen(szImportDLLName)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"\"%s\"",szImportDLLName); + //if(szImportName && strlen(szImportName)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," as \"%s\"",szImportName); + if(szImportName && strlen(szImportName)) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD(" as ")); + szptr = DumpQString(GUICookie, + (char*)szImportName, + g_szAsmCodeIndent, + 80); + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)0)); + if(IsPmNoMangle(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," nomangle"); + if(IsPmCharSetAnsi(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," ansi"); + if(IsPmCharSetUnicode(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," unicode"); + if(IsPmCharSetAuto(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," autochar"); + if(IsPmSupportsLastError(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," lasterr"); + if(IsPmCallConvWinapi(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," winapi"); + if(IsPmCallConvCdecl(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," cdecl"); + if(IsPmCallConvThiscall(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," thiscall"); + if(IsPmCallConvFastcall(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," fastcall"); + if(IsPmCallConvStdcall(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," stdcall"); + if(IsPmBestFitEnabled(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," bestfit:on"); + if(IsPmBestFitDisabled(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," bestfit:off"); + if(IsPmThrowOnUnmappableCharEnabled(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," charmaperror:on"); + if(IsPmThrowOnUnmappableCharDisabled(dwMappingFlags)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," charmaperror:off"); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)-1)); + return szptr; +} + +void DumpByteArray(__inout __nullterminated char* szString, const BYTE* pBlob, ULONG ulLen, void* GUICookie) +{ + ULONG32 ulStrOffset = 0; + ULONG32 j = 0; + ULONG32 k = 0; + ULONG32 m = 0; + char sz[256]; + bool printsz = FALSE; + char* szptr = NULL; + BYTE byt = 0; + + + ulStrOffset = (ULONG32) strlen(szString); + szptr = &szString[ulStrOffset]; + if(!pBlob) ulLen = 0; + for(j = 0, k=0, m=0; j < ulLen; j++,k++,m++) + { + if(k == 16) + { + if(printsz) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(" // %s"),sz); + } + printLine(GUICookie,szString); + strcpy_s(szString,SZSTRING_SIZE,g_szAsmCodeIndent); + for(k=(ULONG32) strlen(szString); k < ulStrOffset; k++) szString[k] = ' '; + szString[k] = 0; + szptr = &szString[ulStrOffset]; + k = 0; + m = 0; + printsz = FALSE; + } + bool bBreak = FALSE; + WIN_PAL_CPP_TRY { + byt = pBlob[j]; + } + WIN_PAL_CPP_CATCH_ALL + { + strcat_s(szString, SZSTRING_SIZE,ERRORMSG("INVALID DATA ADDRESS")); + bBreak = TRUE; + } + WIN_PAL_CPP_ENDTRY; + + if (bBreak) + break; + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%2.2X ",byt); + if(isprint(byt)) + { + if(g_fDumpRTF) + { + if((byt == '\\')||(byt=='{')||(byt=='}')) sz[m++]='\\'; + sz[m] = byt; + } + else if(g_fDumpHTML) + { + if(byt == '<') { sz[m] = 0; strcat_s(sz,256-m,LTN()); m+=(ULONG32)(strlen(LTN())); } + else if(byt == '>') { sz[m] = 0; strcat_s(sz,256-m,GTN()); m+=(ULONG32)(strlen(GTN())); } + else sz[m] = byt; + } + else sz[m] = byt; + printsz = TRUE; + } + else sz[m] = '.'; + sz[m+1] = 0; + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),") "); + if(printsz) + { + for(j = k; j < 16; j++) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," "); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// %s"),sz); + } +} + +mdToken ResolveTypeDefReflectionNotation(IMDInternalImport *pIMDI, + LPCUTF8 szNamespace, + __inout LPUTF8 szName, + mdToken tkEncloser) +{ + mdToken tk = 0; + LPUTF8 pch = strrchr(szName, '+'); + if(pch != NULL) + { + *pch = 0; + tkEncloser = ResolveTypeDefReflectionNotation(pIMDI,szNamespace,szName,tkEncloser); + szNamespace = ""; + szName = pch+1; + } + if(SUCCEEDED(pIMDI->FindTypeDef(szNamespace,szName,tkEncloser,&tk))) + return tk; + else + return 0; +} + +mdToken ResolveTypeRefReflectionNotation(IMDInternalImport *pIMDI, + __in __nullterminated char* szNamespace, + __inout __nullterminated char* szName, + mdToken tkResScope) +{ + mdToken tk = 0; + char* pch = strrchr(szName, '+'); + if(pch != NULL) + { + *pch = 0; + tkResScope = ResolveTypeRefReflectionNotation(pIMDI,szNamespace,szName,tkResScope); + szNamespace = ""; + szName = pch+1; + } + if(SUCCEEDED(pIMDI->FindTypeRefByName((LPCSTR)szNamespace,(LPCSTR)szName,tkResScope,&tk))) + return tk; + else + return 0; +} +mdToken ResolveReflectionNotation(BYTE* dataPtr, + unsigned Lstr, + IMDInternalImport *pIMDI, + void* GUICookie) +{ + char* str = new char[Lstr+1]; + mdToken ret = 0; + if(str) + { + char* szNamespace = ""; + char* szName = str; + char* szAssembly = NULL; + char* pch; + memcpy(str,dataPtr,Lstr); + str[Lstr] = 0; + //format: Namespace.Name, Assembly,... + pch = strchr(str,','); + if(pch) + { + *pch = 0; + for(szAssembly = pch+1; *szAssembly == ' '; szAssembly++); + pch = strchr(szAssembly,','); + if(pch) *pch = 0; + } + pch = strrchr(str,'.'); + if(pch) + { + *pch = 0; + szNamespace = str; + szName = pch+1; + } + if(szAssembly == NULL) + { + // Look in TypeDefs + mdToken tk = ResolveTypeDefReflectionNotation(pIMDI,szNamespace,szName,mdTypeDefNil); + if(tk != 0) + ret = tk; + else + // TypeDef not found, try TypeRef from mscorlib + szAssembly = "mscorlib"; + } + if(szAssembly != NULL) + { + // Look in TypeRefs + // First, identify resolution scope + _ASSERTE(*szName); + ULONG mAsmRefs = pIMDI->GetCountWithTokenKind(mdtAssemblyRef); + if(mAsmRefs) + { + mdToken tkResScope = 0; + mdToken tk=TokenFromRid(mdtAssemblyRef,1), tkmax=TokenFromRid(mdtAssemblyRef,mAsmRefs); + LPCSTR szAsmRefName; + // these are dummies + const void* pPKT, *pHash; + ULONG ulPKT,ulHash; + AssemblyMetaDataInternal MD; + DWORD dwFlags; + + for (;tk <= tkmax; tk++) + { + if (FAILED(pIMDI->GetAssemblyRefProps(tk,&pPKT,&ulPKT,&szAsmRefName,&MD,&pHash,&ulHash,&dwFlags))) + { + continue; + } + if(0==strcmp(szAsmRefName,szAssembly)) + { + tkResScope = tk; + break; + } + } + if(tkResScope) + { + ret = ResolveTypeRefReflectionNotation(pIMDI,szNamespace,szName,tkResScope); + } + } + } + } + VDELETE(str); + return ret; +} + +unsigned UnderlyingTypeOfEnumTypeDef(mdToken tk, IMDInternalImport *pIMDI) +{ + HRESULT hr; + // make sure it's a TypeDef + if(TypeFromToken(tk) != mdtTypeDef) return 0; + + // make sure it's an enum + mdToken tkParent; + DWORD dwAttr; + if (FAILED(pIMDI->GetTypeDefProps(tk,&dwAttr,&tkParent))) + { + return 0; + } + if(RidFromToken(tkParent)==0) return 0; + LPCSTR szName, szNamespace; + switch(TypeFromToken(tkParent)) + { + case mdtTypeDef: + if (FAILED(pIMDI->GetNameOfTypeDef(tkParent, &szName, &szNamespace))) + { + return 0; + } + break; + + case mdtTypeRef: + if (FAILED(pIMDI->GetNameOfTypeRef(tkParent, &szNamespace, &szName))) + { + return 0; + } + break; + + default: + return 0; + } + + if (strcmp(szName,"Enum") != 0 || strcmp(szNamespace,"System") != 0) + { + // the parent type is not System.Enum so this type has no underlying type + return 0; + } + + // OK, it's an enum; find its instance field and get its type + HENUMInternal hEnum; + mdToken tkField; + if (FAILED(pIMDI->EnumInit(mdtFieldDef,tk,&hEnum))) + { + return 0; + } + while(pIMDI->EnumNext(&hEnum,&tkField)) + { + if (FAILED(pIMDI->GetFieldDefProps(tkField, &dwAttr))) + { + continue; + } + if (IsFdStatic(dwAttr)) + { + continue; + } + PCCOR_SIGNATURE psig; + if (FAILED(pIMDI->GetSigOfFieldDef(tkField,(ULONG*)&dwAttr, &psig))) + { + continue; + } + pIMDI->EnumClose(&hEnum); + return (unsigned) *(psig+1); + } + // no instance field found -- error! + pIMDI->EnumClose(&hEnum); + return 0; +} +mdToken TypeRefToTypeDef(mdToken tk, IMDInternalImport *pIMDI, IMDInternalImport **ppIMDInew) +{ + mdToken tkEncloser = mdTypeDefNil; + mdToken tkTypeDef = mdTypeDefNil; + *ppIMDInew = NULL; + + // get the resolution scope of TypeRef + mdToken tkRS; + if (FAILED(pIMDI->GetResolutionScopeOfTypeRef(tk, &tkRS))) + { + goto AssignAndReturn; + } + if (TypeFromToken(tkRS) == mdtTypeRef) + tkEncloser = TypeRefToTypeDef(tkRS,pIMDI,ppIMDInew); + else if (TypeFromToken(tkRS) == mdtAssemblyRef) + { + *ppIMDInew = g_asmref_import[RidFromToken(tkRS)]; + if (*ppIMDInew == NULL) + { + // get that assembly and open IMDInternalImport + IMetaDataAssemblyImport* pAssemblyImport; + if (FAILED(g_pPubImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &pAssemblyImport))) + goto AssignAndReturn; + + const void *pPKT, *pHash; + ULONG cHash,cName; + WCHAR wzName[2048]; + ASSEMBLYMETADATA md; + WCHAR wzLocale[1024]; + DWORD dwFlags; + IUnknown* pIAMDI[64]; + memset(&md,0,sizeof(ASSEMBLYMETADATA)); + md.szLocale = wzLocale; + md.cbLocale = 1024; + + struct Param + { + IMetaDataAssemblyImport* pAssemblyImport; + WCHAR *wzName; + IUnknown **pIAMDI; + ULONG cPKT; + } param; + param.pAssemblyImport = pAssemblyImport; + param.wzName = wzName; + param.pIAMDI = pIAMDI; + + pAssemblyImport->GetAssemblyRefProps(tkRS,&pPKT,¶m.cPKT,wzName,2048,&cName,&md,&pHash,&cHash,&dwFlags); + + PAL_TRY(Param *, pParam, ¶m) { + if(FAILED(pParam->pAssemblyImport->FindAssembliesByName(NULL,NULL,(LPCWSTR)pParam->wzName,pParam->pIAMDI,64,&pParam->cPKT))) + pParam->cPKT=0; + } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + param.cPKT=0; + } PAL_ENDTRY + + pAssemblyImport->Release(); + if(param.cPKT == 0) goto AssignAndReturn; + _ASSERTE(pIAMDI[0] != NULL); + + IUnknown *pUnk; + if(FAILED(pIAMDI[0]->QueryInterface(IID_IUnknown, (void**)&pUnk))) goto AssignAndReturn; + + if (FAILED(g_pCLRRuntimeHostInternal->GetMetaDataInternalInterfaceFromPublic( + pUnk, + IID_IMDInternalImport, + (LPVOID *)ppIMDInew))) + { + goto AssignAndReturn; + } + _ASSERTE(*ppIMDInew != NULL); + g_asmref_import[RidFromToken(tkRS)] = *ppIMDInew; + pUnk->Release(); + for(cHash=0; cHash<param.cPKT; cHash++) + if(pIAMDI[cHash]) pIAMDI[cHash]->Release(); + } + } + if (*ppIMDInew != NULL) + { + LPCSTR szName, szNamespace; + if (FAILED(pIMDI->GetNameOfTypeRef(tk, &szNamespace, &szName))) + { + tkTypeDef = mdTypeDefNil; + goto AssignAndReturn; + } + + if (FAILED((*ppIMDInew)->FindTypeDef(szNamespace,szName,tkEncloser,&tkTypeDef))) + { + tkTypeDef = mdTypeDefNil; + } + } +AssignAndReturn: + return tkTypeDef; +} +unsigned UnderlyingTypeOfEnum(mdToken tk, IMDInternalImport *pIMDI) +{ + unsigned uRet = 0; + unsigned ix = RidFromToken(tk); + if(TypeFromToken(tk)==mdtTypeDef) + { + if(g_enum_td_type[ix] == 0xFF) + { + g_enum_td_type[ix] = (BYTE)UnderlyingTypeOfEnumTypeDef(tk,pIMDI); + } + return (unsigned)g_enum_td_type[ix]; + } + else if(TypeFromToken(tk)==mdtTypeRef) + { + if(g_enum_tr_type[ix] == 0xFF) + { + IMDInternalImport *pIMDInew = NULL; + mdToken tkTypeDef = TypeRefToTypeDef(tk,pIMDI, &pIMDInew); + if((RidFromToken(tkTypeDef)!=0)&&(pIMDInew != NULL)) + { + uRet = UnderlyingTypeOfEnumTypeDef(tkTypeDef,pIMDInew); + } + g_enum_tr_type[ix] = (BYTE)uRet; + } + return (unsigned)g_enum_tr_type[ix]; + } + else return 0; +} + +/**************************************************************************/ +/* move 'ptr past the exactly one type description */ + +BYTE* skipType(BYTE* ptr) +{ + mdToken tk; +AGAIN: + switch(*ptr++) { + case ELEMENT_TYPE_VOID : + case ELEMENT_TYPE_BOOLEAN : + case ELEMENT_TYPE_CHAR : + case ELEMENT_TYPE_I1 : + case ELEMENT_TYPE_U1 : + case ELEMENT_TYPE_I2 : + case ELEMENT_TYPE_U2 : + case ELEMENT_TYPE_I4 : + case ELEMENT_TYPE_U4 : + case ELEMENT_TYPE_I8 : + case ELEMENT_TYPE_U8 : + case ELEMENT_TYPE_R4 : + case ELEMENT_TYPE_R8 : + case ELEMENT_TYPE_U : + case ELEMENT_TYPE_I : + case ELEMENT_TYPE_STRING : + case ELEMENT_TYPE_OBJECT : + case ELEMENT_TYPE_TYPEDBYREF : + case ELEMENT_TYPE_SENTINEL : + case SERIALIZATION_TYPE_TYPE : + case SERIALIZATION_TYPE_TAGGED_OBJECT : + /* do nothing */ + break; + + case SERIALIZATION_TYPE_ENUM : + { + unsigned Lstr = CorSigUncompressData((PCCOR_SIGNATURE&)ptr); + ptr += Lstr; + break; + } + + case ELEMENT_TYPE_VALUETYPE : + case ELEMENT_TYPE_CLASS : + ptr += CorSigUncompressToken(ptr, &tk); + break; + + case ELEMENT_TYPE_CMOD_REQD : + case ELEMENT_TYPE_CMOD_OPT : + ptr += CorSigUncompressToken(ptr, &tk); + goto AGAIN; + + case ELEMENT_TYPE_ARRAY : + { + ptr = skipType(ptr); // element Type + unsigned rank = CorSigUncompressData((PCCOR_SIGNATURE&) ptr); + if (rank != 0) + { + unsigned numSizes = CorSigUncompressData((PCCOR_SIGNATURE&) ptr); + while(numSizes > 0) + { + CorSigUncompressData((PCCOR_SIGNATURE&) ptr); + --numSizes; + } + unsigned numLowBounds = CorSigUncompressData((PCCOR_SIGNATURE&) ptr); + while(numLowBounds > 0) + { + CorSigUncompressData((PCCOR_SIGNATURE&) ptr); + --numLowBounds; + } + } + } + break; + + // Modifiers or depedant types + case ELEMENT_TYPE_PINNED : + case ELEMENT_TYPE_PTR : + case ELEMENT_TYPE_BYREF : + case ELEMENT_TYPE_SZARRAY : + // tail recursion optimization + // ptr = skipType(ptr, fFixupType); + // break + goto AGAIN; + + case ELEMENT_TYPE_VAR: + case ELEMENT_TYPE_MVAR: + CorSigUncompressData((PCCOR_SIGNATURE&) ptr); // bound + break; + + case ELEMENT_TYPE_FNPTR: + { + CorSigUncompressData((PCCOR_SIGNATURE&) ptr); // calling convention + unsigned argCnt = CorSigUncompressData((PCCOR_SIGNATURE&) ptr); // arg count + ptr = skipType(ptr); // return type + while(argCnt > 0) + { + ptr = skipType(ptr); + --argCnt; + } + } + break; + + case ELEMENT_TYPE_GENERICINST: + { + ptr = skipType(ptr); // type constructor + unsigned argCnt = CorSigUncompressData((PCCOR_SIGNATURE&)ptr); // arg count + while(argCnt > 0) { + ptr = skipType(ptr); + --argCnt; + } + } + break; + + default: + case ELEMENT_TYPE_END : + _ASSERTE(!"Unknown Type"); + break; + } + return(ptr); +} + + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +BYTE* PrettyPrintCABlobValue(PCCOR_SIGNATURE &typePtr, + BYTE* dataPtr, + BYTE* dataEnd, + CQuickBytes* out, + IMDInternalImport *pIMDI, + void* GUICookie) +{ + char str[64]; + char appendix[64]; + int typ; + BOOL Reiterate; + BOOL CloseParenthesis; + unsigned numElements = 1; + unsigned n,Lstr; + unsigned underType; + mdToken tk; + + appendix[0] = 0; + do { + if(dataPtr >= dataEnd) + { + _ASSERTE(!"CA blob too short"); + return FALSE; + } + Reiterate = FALSE; + CloseParenthesis = TRUE; + switch(typ = *typePtr++) { + case ELEMENT_TYPE_VOID : + return NULL; + case ELEMENT_TYPE_BOOLEAN : + appendStr(out,KEYWORD("bool")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + appendStr(out,(*dataPtr)? KEYWORD("true"):KEYWORD("false")); + dataPtr++; + } + break; + case ELEMENT_TYPE_CHAR : + appendStr(out,KEYWORD("char")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"0x%4.4X",(WORD)GET_UNALIGNED_VAL16(dataPtr)); + appendStr(out,str); + dataPtr += 2; + } + break; + case ELEMENT_TYPE_I1 : + appendStr(out,KEYWORD("int8")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%d",*((char*)dataPtr)); + appendStr(out,str); + dataPtr ++; + } + break; + case ELEMENT_TYPE_U1 : + appendStr(out,KEYWORD("uint8")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%d",*dataPtr); + appendStr(out,str); + dataPtr ++; + } + break; + case ELEMENT_TYPE_I2 : + appendStr(out,KEYWORD("int16")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%d",GET_UNALIGNED_VAL16(dataPtr)); + appendStr(out,str); + dataPtr +=2; + } + break; + case ELEMENT_TYPE_U2 : + appendStr(out,KEYWORD("uint16")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%d",(WORD)GET_UNALIGNED_VAL16(dataPtr)); + appendStr(out,str); + dataPtr +=2; + } + break; + case ELEMENT_TYPE_I4 : + appendStr(out,KEYWORD("int32")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%d",GET_UNALIGNED_VAL32(dataPtr)); + appendStr(out,str); + dataPtr +=4; + } + break; + case ELEMENT_TYPE_U4 : + appendStr(out,KEYWORD("uint32")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%d",(unsigned)GET_UNALIGNED_VAL32(dataPtr)); + appendStr(out,str); + dataPtr +=4; + } + break; + case ELEMENT_TYPE_I8 : + appendStr(out,KEYWORD("int64")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%I64d",GET_UNALIGNED_VAL64(dataPtr)); + appendStr(out,str); + dataPtr +=8; + } + break; + case ELEMENT_TYPE_U8 : + appendStr(out,KEYWORD("uint64")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + sprintf_s(str,64,"%I64d",(ULONGLONG)GET_UNALIGNED_VAL64(dataPtr)); + appendStr(out,str); + dataPtr +=8; + } + break; + case ELEMENT_TYPE_R4 : + appendStr(out,KEYWORD("float32")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + _gcvt_s(str,64,*((float*)dataPtr), 8); + float df = (float)atof(str); + // Must compare as underlying bytes, not floating point otherwise optmizier will + // try to enregister and comapre 80-bit precision number with 32-bit precision number!!!! + if((*(ULONG*)&df != (ULONG)GET_UNALIGNED_VAL32(dataPtr))||(strchr(str,'#') != NULL)) + sprintf_s(str, 64,"0x%08X",(ULONG)GET_UNALIGNED_VAL32(dataPtr)); + appendStr(out,str); + dataPtr +=4; + } + break; + + case ELEMENT_TYPE_R8 : + appendStr(out,KEYWORD("float64")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + char *pch; + _gcvt_s(str,64,*((double*)dataPtr), 17); + double df = strtod(str, &pch); + // Must compare as underlying bytes, not floating point otherwise optmizier will + // try to enregister and comapre 80-bit precision number with 64-bit precision number!!!! + if((*(ULONGLONG*)&df != (ULONGLONG)GET_UNALIGNED_VAL64(dataPtr))||(strchr(str,'#') != NULL)) + sprintf_s(str, 64, "0x%I64X",(ULONGLONG)GET_UNALIGNED_VAL64(dataPtr)); + appendStr(out,str); + dataPtr +=8; + } + break; + case ELEMENT_TYPE_U : + case ELEMENT_TYPE_I : + return NULL; + + case ELEMENT_TYPE_OBJECT : + case SERIALIZATION_TYPE_TAGGED_OBJECT: + appendStr(out,KEYWORD("object")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + BYTE* dataPtr1 = skipType(dataPtr); + if(n) appendStr(out," "); + + dataPtr = PrettyPrintCABlobValue((PCCOR_SIGNATURE&)dataPtr, dataPtr1, dataEnd, out, pIMDI,GUICookie); + if (dataPtr == NULL) return NULL; + } + break; + case ELEMENT_TYPE_STRING : + appendStr(out,KEYWORD("string")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + if(*dataPtr == 0xFF) + { + appendStr(out,KEYWORD("nullref")); + Lstr = 1; + } + else + { + appendStr(out,"'"); + Lstr = CorSigUncompressData((PCCOR_SIGNATURE&)dataPtr); + if(dataPtr + Lstr > dataEnd) return NULL; + appendStr(out,UnquotedProperName((char*)dataPtr,Lstr)); + appendStr(out,"'"); + } + dataPtr += Lstr; + } + break; + case ELEMENT_TYPE_CLASS : + typePtr += CorSigUncompressToken(typePtr, &tk); //skip the following token + case SERIALIZATION_TYPE_TYPE : + appendStr(out,KEYWORD("type")); + appendStr(out,appendix); + appendStr(out,"("); + for(n=0; n < numElements; n++) + { + if(n) appendStr(out," "); + if(*dataPtr == 0xFF) + { + appendStr(out,KEYWORD("nullref")); + Lstr = 1; + } + else + { + Lstr = CorSigUncompressData((PCCOR_SIGNATURE&)dataPtr); + if(dataPtr + Lstr > dataEnd) return NULL; + tk = ResolveReflectionNotation(dataPtr,Lstr,pIMDI,GUICookie); + if(IsNilToken(tk)) + { + appendStr(out,KEYWORD("class ")); + appendStr(out,"'"); + appendStr(out,UnquotedProperName((char*)dataPtr,Lstr)); + appendStr(out,"'"); + } + else + { + PrettyPrintClass(out, tk, pIMDI); + } + } + dataPtr += Lstr; + } + break; + + + case ELEMENT_TYPE_VALUETYPE : + typePtr += CorSigUncompressToken(typePtr, &tk); + _ASSERTE(pIMDI->IsValidToken(tk)); + goto GetUTSize; + + case SERIALIZATION_TYPE_ENUM : + Lstr = CorSigUncompressData((PCCOR_SIGNATURE&)typePtr); + tk = ResolveReflectionNotation((BYTE*)typePtr,Lstr,pIMDI,GUICookie); + /* + if(IsNilToken(tk)) + { + _ASSERTE(!"Failed to resolve Reflection notation for S_T_ENUM"); + return NULL; + } + */ + typePtr += Lstr; + + GetUTSize: + underType = UnderlyingTypeOfEnum(tk, pIMDI); + if(underType == 0) + { + // try to figure out the underlying type by its size + switch(dataEnd - dataPtr) + { + case 1: // bool + underType = ELEMENT_TYPE_BOOLEAN; + break; + case 2: // int16 + underType = ELEMENT_TYPE_I2; + break; + case 4: // int32 + underType = ELEMENT_TYPE_I4; + break; + case 8: // int64 + underType = ELEMENT_TYPE_I8; + break; + default: + return NULL; + } + //_ASSERTE(!"Failed to find underlying type for S_T_ENUM"); + } + { + PCCOR_SIGNATURE ps = (PCCOR_SIGNATURE)&underType; + dataPtr = PrettyPrintCABlobValue(ps, dataPtr, dataEnd, out, pIMDI,GUICookie); + } + CloseParenthesis = FALSE; + break; + + + case ELEMENT_TYPE_SZARRAY : + numElements *= (unsigned)GET_UNALIGNED_VAL32(dataPtr); + Reiterate = TRUE; + sprintf_s(appendix,64,"[%d]",numElements); + if(numElements == 0xFFFFFFFF) + numElements = 0; + dataPtr += 4; + break; + + case ELEMENT_TYPE_ARRAY : + case ELEMENT_TYPE_VAR : + case ELEMENT_TYPE_MVAR : + case ELEMENT_TYPE_FNPTR : + case ELEMENT_TYPE_GENERICINST : + case ELEMENT_TYPE_TYPEDBYREF : + +#ifdef LOGGING + case ELEMENT_TYPE_INTERNAL : +#endif // LOGGING + return NULL; + + + // Modifiers or depedent types + case ELEMENT_TYPE_CMOD_OPT : + case ELEMENT_TYPE_CMOD_REQD : + case ELEMENT_TYPE_PINNED : + Reiterate = TRUE; + break; + + case ELEMENT_TYPE_PTR : + case ELEMENT_TYPE_BYREF : + return NULL; + + default: + case ELEMENT_TYPE_SENTINEL : + case ELEMENT_TYPE_END : + _ASSERTE(!"Unknown Type"); + return NULL; + } // end switch + } while(Reiterate); + if(CloseParenthesis) appendStr(out,")"); + return dataPtr; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +BOOL PrettyPrintCustomAttributeNVPairs(unsigned nPairs, BYTE* dataPtr, BYTE* dataEnd, CQuickBytes* out, void* GUICookie) +{ + IMDInternalImport *pIMDI = g_pImport; // ptr to IMDInternalImport class with ComSig + while(dataPtr < dataEnd) + { + // field or property? + switch(*dataPtr) + { + case SERIALIZATION_TYPE_FIELD: + appendStr(out,KEYWORD("field ")); + break; + case SERIALIZATION_TYPE_PROPERTY: + appendStr(out,KEYWORD("property ")); + break; + default: + _ASSERTE(!"Invalid code of name/val pair in CA blob"); + return FALSE; + } + dataPtr++; + if(dataPtr >= dataEnd) + { + _ASSERTE(!"CA blob too short"); + return FALSE; + } + // type of the field/property + PCCOR_SIGNATURE dataTypePtr = (PCCOR_SIGNATURE)dataPtr; + char* szAppend = ""; + if(*dataPtr == ELEMENT_TYPE_SZARRAY) // Only SZARRAY modifier can occur in ser.type + { + szAppend = "[]"; + dataPtr++; + } + if(*dataPtr == SERIALIZATION_TYPE_TYPE) + { + appendStr(out,KEYWORD("type")); + dataPtr++; + } + else if(*dataPtr == SERIALIZATION_TYPE_TAGGED_OBJECT) + { + appendStr(out,KEYWORD("object")); + dataPtr++; + } + else if(*dataPtr == SERIALIZATION_TYPE_ENUM) + { + appendStr(out,KEYWORD("enum ")); + dataPtr++; + unsigned Lstr = CorSigUncompressData((PCCOR_SIGNATURE&)dataPtr); + if(dataPtr + Lstr > dataEnd) return FALSE; + mdToken tk = ResolveReflectionNotation(dataPtr,Lstr,pIMDI,GUICookie); + if(IsNilToken(tk)) + { + appendStr(out,KEYWORD("class ")); + appendStr(out,"'"); + appendStr(out,UnquotedProperName((char*)dataPtr,Lstr)); + appendStr(out,"'"); + } + else + { + PrettyPrintClass(out, tk, pIMDI); + } + dataPtr += Lstr; + } + else + { + szAppend = ""; + dataPtr = (BYTE*)PrettyPrintType(dataTypePtr, out, pIMDI); + } + if(*szAppend != 0) + appendStr(out,szAppend); + if(dataPtr >= dataEnd) + { + _ASSERTE(!"CA blob too short"); + return FALSE; + } + // name of the field/property + unsigned Lstr = CorSigUncompressData((PCCOR_SIGNATURE&)dataPtr); + if(dataPtr + Lstr > dataEnd) return FALSE; + appendStr(out," '"); + appendStr(out,UnquotedProperName((char*)dataPtr,Lstr)); + appendStr(out,"' = "); + dataPtr += Lstr; + if(dataPtr >= dataEnd) + { + _ASSERTE(!"CA blob too short"); + return FALSE; + } + // value of the field/property + dataPtr = PrettyPrintCABlobValue(dataTypePtr, dataPtr, dataEnd, out, pIMDI,GUICookie); + if(NULL == dataPtr) return FALSE; + appendStr(out,"\n"); + + nPairs--; + } + _ASSERTE(nPairs == 0); + return TRUE; +} +BOOL PrettyPrintCustomAttributeBlob(mdToken tkType, BYTE* pBlob, ULONG ulLen, void* GUICookie, __inout __nullterminated char* szString) +{ + HRESULT hr; + char* initszptr = szString + strlen(szString); + PCCOR_SIGNATURE typePtr; // type to convert, + ULONG typeLen; // the lenght of 'typePtr' + CHECK_LOCAL_STATIC_VAR(static CQuickBytes out); // where to put the pretty printed string + + IMDInternalImport *pIMDI = g_pImport; // ptr to IMDInternalImport class with ComSig + unsigned numArgs = 0; + unsigned numTyArgs = 0; + PCCOR_SIGNATURE typeEnd; + unsigned callConv; + BYTE* dataPtr = pBlob; + BYTE* dataEnd = dataPtr + ulLen; + WORD wNumNVPairs = 0; + unsigned numElements = 0; + + if(TypeFromToken(tkType) == mdtMemberRef) + { + const char *szName_Ignore; + if (FAILED(pIMDI->GetNameAndSigOfMemberRef(tkType,&typePtr,&typeLen, &szName_Ignore))) + { + return FALSE; + } + } + else if(TypeFromToken(tkType) == mdtMethodDef) + { + if (FAILED(pIMDI->GetSigOfMethodDef(tkType, &typeLen, &typePtr))) + { + return FALSE; + } + } + else + return FALSE; + typeEnd = typePtr + typeLen; + + callConv = CorSigUncompressData(typePtr); + + if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + numTyArgs = CorSigUncompressData(typePtr); + return FALSE; // leave generic instantiations for later + } + numElements = numArgs = CorSigUncompressData(typePtr); + out.Shrink(0); + if (!isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_GENERICINST)) + { + // skip return type + typePtr = PrettyPrintType(typePtr, &out, pIMDI); + out.Shrink(0); + } + appendStr(&out," = {"); + dataPtr += 2; // skip blob prolog 0x0001 + // dump the arguments + while(typePtr < typeEnd) + { + if (*typePtr == ELEMENT_TYPE_SENTINEL) + { + typePtr++; + } + else + { + if (numArgs <= 0) + break; + dataPtr = PrettyPrintCABlobValue(typePtr, dataPtr, dataEnd-2, &out, pIMDI,GUICookie); + if(NULL == dataPtr) return FALSE; + appendStr(&out,"\n"); + --numArgs; + } + } + _ASSERTE(numArgs == 0); + wNumNVPairs = (WORD)GET_UNALIGNED_VAL16(dataPtr); + dataPtr+=2; + numElements += wNumNVPairs; + // arguments done, now to field/property name-val pairs + + if(!PrettyPrintCustomAttributeNVPairs((unsigned) wNumNVPairs, dataPtr, dataEnd, &out, GUICookie)) + return FALSE; + + { + char* sz = asString(&out); + char* ch = sz; + char* szbl; + while((ch = strchr(ch,'\n'))) + { + *ch = 0; + ch++; + } + // if the string is too long already, begin on next line + if((initszptr - szString) > 80) + { + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s ",g_szAsmCodeIndent); + initszptr = &szString[strlen(szString)]; + } + sprintf_s(initszptr,SZSTRING_REMAINING_SIZE(initszptr), "%s", sz); + initszptr += 4; // to compensate for " = {" + szbl = szString + strlen(g_szAsmCodeIndent); + for(unsigned n = 1; n < numElements; n++) + { + printLine(GUICookie, szString); + sz = sz + strlen(sz) + 1; + for(ch = szbl; ch < initszptr; ch++) *ch = ' '; + sprintf_s(initszptr,SZSTRING_REMAINING_SIZE(initszptr), "%s", sz); + } + } + strcat_s(initszptr, SZSTRING_REMAINING_SIZE(initszptr),"}"); + if(g_fShowBytes) + { + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," // "); + sprintf_s(szString,SZSTRING_SIZE,"%s = ( ",g_szAsmCodeIndent); + DumpByteArray(szString,pBlob,ulLen,GUICookie); + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-8] = 0; + } + return TRUE; +} + +void DumpCustomAttributeProps(mdToken tkCA, mdToken tkType, mdToken tkOwner, BYTE* pBlob, ULONG ulLen, void *GUICookie, bool bWithOwner) +{ + HRESULT hr; + char* szptr = &szString[0]; + BOOL fCommentItOut = FALSE; + if((TypeFromToken(tkType) == mdtMemberRef)||(TypeFromToken(tkType) == mdtMethodDef)) + { + mdToken tkParent; + const char * pszClassName = NULL; + const char * pszNamespace = NULL; + if (TypeFromToken(tkType) == mdtMemberRef) + { + if (FAILED(g_pImport->GetParentOfMemberRef(tkType, &tkParent))) + { + szptr += sprintf_s(szptr, SZSTRING_REMAINING_SIZE(szptr), "Invalid MemberRef %08X record ", tkType); + return; + } + } + else + { + if (FAILED(g_pImport->GetParentToken(tkType, &tkParent))) + { + szptr += sprintf_s(szptr, SZSTRING_REMAINING_SIZE(szptr), "Invalid token %08X ", tkType); + return; + } + } + + REGISTER_REF(tkOwner,tkType); // owner of the CA references the class amd method + REGISTER_REF(tkOwner,tkParent); + + if (TypeFromToken(tkParent) == mdtTypeDef) + { + if (FAILED(g_pImport->GetNameOfTypeDef(tkParent, &pszClassName, &pszNamespace))) + { + szptr += sprintf_s(szptr, SZSTRING_REMAINING_SIZE(szptr), "Invalid TypeDef %08X record ", tkParent); + return; + } + } + else if (TypeFromToken(tkParent) == mdtTypeRef) + { + if (FAILED(g_pImport->GetNameOfTypeRef(tkParent, &pszNamespace, &pszClassName))) + { + szptr += sprintf_s(szptr, SZSTRING_REMAINING_SIZE(szptr), "Invalid TypeRef %08X record ", tkParent); + return; + } + } + if(pszClassName && pszNamespace + && (strcmp(pszNamespace,"System.Diagnostics") == 0) + && (strcmp(pszClassName,"DebuggableAttribute") == 0)) fCommentItOut = TRUE; + + + } + if(fCommentItOut) + { + printLine(GUICookie,COMMENT((char*)0)); // start multiline comment + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_AUTOCA),g_szAsmCodeIndent); + printLine(GUICookie, szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH,"// "); + } + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".custom")); + if(bWithOwner) + { + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),tkCA); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"("); + switch(TypeFromToken(tkOwner)) + { + case mdtTypeDef : + case mdtTypeRef : + case mdtTypeSpec: + PrettyPrintToken(szString, tkOwner, g_pImport,GUICookie,0); + break; + + case mdtMemberRef: + { + PCCOR_SIGNATURE typePtr; + const char* pszMemberName; + ULONG cComSig; + + pszMemberName; + if (FAILED(g_pImport->GetNameAndSigOfMemberRef( + tkOwner, + &typePtr, + &cComSig, + &pszMemberName))) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"ERROR "); + break; + } + unsigned callConv = CorSigUncompressData(typePtr); + + if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD)) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("field ")); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("method ")); + PrettyPrintToken(szString, tkOwner, g_pImport,GUICookie,0); + } + break; + + case mdtMethodDef: + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), KEYWORD("method ")); + PrettyPrintToken(szString, tkOwner, g_pImport,GUICookie,0); + break; + + default : + strcat_s(szString, SZSTRING_REMAINING_SIZE(szptr),ERRORMSG("UNKNOWN_OWNER")); + break; + } + szptr = &szString[strlen(szString)]; + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),tkOwner); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),") "); + } + else + { + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X:%08X*/ "),tkCA,tkType); + } + switch(TypeFromToken(tkType)) + { + case mdtTypeDef : + case mdtTypeRef : + case mdtMemberRef: + case mdtMethodDef: + PrettyPrintToken(szString, tkType, g_pImport,GUICookie,0); + break; + + default : + strcat_s(szString, SZSTRING_SIZE,ERRORMSG("UNNAMED_CUSTOM_ATTR")); + break; + } + szptr = &szString[strlen(szString)]; + + if(pBlob && ulLen) + { + if(!g_fCAVerbal || !PrettyPrintCustomAttributeBlob(tkType, pBlob, ulLen, GUICookie, szString)) + { + sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = ( "); + DumpByteArray(szString,pBlob,ulLen,GUICookie); + } + } + printLine(GUICookie, szString); + if(fCommentItOut) + { + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-4] = 0; + printLine(GUICookie,COMMENT((char*)-1)); // end multiline comment + } +} + +void DumpCustomAttribute(mdCustomAttribute tkCA, void *GUICookie, bool bWithOwner) +{ + mdToken tkType; + BYTE* pBlob=NULL; + ULONG ulLen=0; + mdToken tkOwner; + static mdToken tkMod = 0xFFFFFFFF; + + _ASSERTE((TypeFromToken(tkCA)==mdtCustomAttribute)&&(RidFromToken(tkCA)>0)); + _ASSERTE(RidFromToken(tkCA) <= g_uNCA); + if(tkMod == 0xFFFFFFFF) tkMod = g_pImport->GetModuleFromScope(); + + // can't use InternalImport here: need the tkOwner + if (FAILED(g_pPubImport->GetCustomAttributeProps( // S_OK or error. + tkCA, // [IN] CustomValue token. + &tkOwner, // [OUT, OPTIONAL] Object token. + &tkType, // [OUT, OPTIONAL] Put TypeDef/TypeRef token here. + (const void **)&pBlob, // [OUT, OPTIONAL] Put pointer to data here. + &ulLen))) // [OUT, OPTIONAL] Put size of date here. + { + return; + } + + if(!RidFromToken(tkOwner)) return; + + DWORD i; + for(i = 0; i < g_NumTypedefs; i++) + { + TypeDefDescr* pTDD = &((*g_typedefs)[i]); + if(TypeFromToken(pTDD->tkTypeSpec) == mdtCustomAttribute) + { + mdToken tkTypeTD; + mdToken tkOwnerTD; + BYTE* pBlobTD=NULL; + ULONG uLenTD=0; + tkTypeTD = GET_UNALIGNED_VAL32(pTDD->psig); + if(tkTypeTD != tkType) continue; + + tkOwnerTD = GET_UNALIGNED_VAL32(pTDD->psig + sizeof(mdToken)); + if(pTDD->cb > 2*sizeof(mdToken)) + { + pBlobTD = (BYTE*)pTDD->psig + 2*sizeof(mdToken); + uLenTD = pTDD->cb - 2*sizeof(mdToken); + } + if(uLenTD != ulLen) continue; + if(memcmp(pBlobTD,pBlob,ulLen) != 0) continue; + char* szptr = &szString[0]; + szString[0] = 0; + szptr += sprintf_s(szString,SZSTRING_SIZE,"%s%s", g_szAsmCodeIndent,JUMPPT(ProperName(pTDD->szName),pTDD->tkSelf)); + if(g_fDumpTokens) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),tkCA); + printLine(GUICookie,szString); + break; + } + } + if(i >= g_NumTypedefs) + DumpCustomAttributeProps(tkCA,tkType,tkOwner,pBlob,ulLen,GUICookie,bWithOwner); + _ASSERTE(g_rchCA); + _ASSERTE(RidFromToken(tkCA) <= g_uNCA); + g_rchCA[RidFromToken(tkCA)] = 1; +} + +void DumpCustomAttributes(mdToken tkOwner, void *GUICookie) +{ + if (g_fShowCA) + { + HENUMInternal hEnum; + mdCustomAttribute tkCA; + + if (FAILED(g_pImport->EnumInit(mdtCustomAttribute, tkOwner,&hEnum))) + { + return; + } + while(g_pImport->EnumNext(&hEnum,&tkCA) && RidFromToken(tkCA)) + { + DumpCustomAttribute(tkCA,GUICookie,false); + } + g_pImport->EnumClose( &hEnum); + } +} + +void DumpDefaultValue(mdToken tok, __inout __nullterminated char* szString, void* GUICookie) +{ + MDDefaultValue MDDV; + char* szptr = &szString[strlen(szString)]; + + if (FAILED(g_pImport->GetDefaultValue(tok, &MDDV))) + { + szptr += sprintf_s(szptr, SZSTRING_REMAINING_SIZE(szptr), ERRORMSG(" /* Invalid default value for %08X: */"), tok); + return; + } + switch(MDDV.m_bType) + { + case ELEMENT_TYPE_VOID: + strcat_s(szString, SZSTRING_SIZE," /* NO CORRESPONDING RECORD IN CONSTANTS TABLE */"); + break; + case ELEMENT_TYPE_I1: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%02X)",KEYWORD("int8"),MDDV.m_byteValue); + break; + case ELEMENT_TYPE_U1: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%02X)",KEYWORD("uint8"),MDDV.m_byteValue); + break; + case ELEMENT_TYPE_I2: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%04X)",KEYWORD("int16"),MDDV.m_usValue); + break; + case ELEMENT_TYPE_U2: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%04X)",KEYWORD("uint16"),MDDV.m_usValue); + break; + case ELEMENT_TYPE_I4: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%08X)",KEYWORD("int32"),MDDV.m_ulValue); + break; + case ELEMENT_TYPE_U4: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%08X)",KEYWORD("uint32"),MDDV.m_ulValue); + break; + case ELEMENT_TYPE_CHAR: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%04X)",KEYWORD("char"),MDDV.m_usValue); + break; + case ELEMENT_TYPE_BOOLEAN: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s",KEYWORD("bool")); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(%s)", KEYWORD((char *)(MDDV.m_byteValue ? "true" : "false"))); + break; + case ELEMENT_TYPE_I8: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%I64X)",KEYWORD("int64"),MDDV.m_ullValue); + break; + case ELEMENT_TYPE_U8: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(0x%I64X)",KEYWORD("uint64"),MDDV.m_ullValue); + break; + case ELEMENT_TYPE_R4: + { + char szf[32]; + _gcvt_s(szf,32,MDDV.m_fltValue, 8); + float df = (float)atof(szf); + // Must compare as underlying bytes, not floating point otherwise optmizier will + // try to enregister and comapre 80-bit precision number with 32-bit precision number!!!! + if((*(ULONG*)&df == MDDV.m_ulValue)&&(strchr(szf,'#') == NULL)) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(%s)",KEYWORD("float32"),szf); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), " = %s(0x%08X)",KEYWORD("float32"),MDDV.m_ulValue); + + } + break; + case ELEMENT_TYPE_R8: + { + char szf[32], *pch; + _gcvt_s(szf,32,MDDV.m_dblValue, 17); + double df = strtod(szf, &pch); //atof(szf); + szf[31]=0; + // Must compare as underlying bytes, not floating point otherwise optmizier will + // try to enregister and comapre 80-bit precision number with 64-bit precision number!!!! + if((*(ULONGLONG*)&df == MDDV.m_ullValue)&&(strchr(szf,'#') == NULL)) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s(%s)",KEYWORD("float64"),szf); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), " = %s(0x%I64X) // %s",KEYWORD("float64"),MDDV.m_ullValue,szf); + } + break; + + case ELEMENT_TYPE_STRING: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = "); + WIN_PAL_CPP_TRY { + szptr = DumpUnicodeString(GUICookie,szString,(WCHAR*)MDDV.m_wzValue,MDDV.m_cbSize/sizeof(WCHAR)); + } WIN_PAL_CPP_CATCH_ALL { + strcat_s(szString, SZSTRING_SIZE,ERRORMSG("INVALID DATA ADDRESS")); + } WIN_PAL_CPP_ENDTRY; + break; + + case ELEMENT_TYPE_CLASS: + if(MDDV.m_wzValue==NULL) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = %s",KEYWORD("nullref")); + break; + } + //else fall thru to default case, to report the error + + default: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG(" /* ILLEGAL CONSTANT type:0x%02X, size:%d bytes, blob: "),MDDV.m_bType,MDDV.m_cbSize); + if(MDDV.m_wzValue) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"("); + WIN_PAL_CPP_TRY { + DumpByteArray(szString,(BYTE*)MDDV.m_wzValue,MDDV.m_cbSize,GUICookie); + } WIN_PAL_CPP_CATCH_ALL { + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG(" Invalid blob at 0x%08X)"), MDDV.m_wzValue); + } WIN_PAL_CPP_ENDTRY + } + else + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"NULL"); + } + strcat_s(szString, SZSTRING_REMAINING_SIZE(szptr), " */"); + break; + } +} + +void DumpParams(ParamDescriptor* pPD, ULONG ulParams, void* GUICookie) +{ + if(pPD) + { + for(ULONG i = ulParams; i<2*ulParams+1; i++) // pPD[ulParams] is return value + { + ULONG j = i % (ulParams+1); + if(RidFromToken(pPD[j].tok)) + { + HENUMInternal hEnum; + mdCustomAttribute tkCA; + ULONG ulCAs= 0; + + if(g_fShowCA) + { + if (FAILED(g_pImport->EnumInit(mdtCustomAttribute, pPD[j].tok, &hEnum))) + { + sprintf_s(szString, SZSTRING_SIZE, "%sERROR: MetaData error enumerating CustomAttribute for %08X", g_szAsmCodeIndent, pPD[j].tok); + printLine(GUICookie, szString); + continue; + } + ulCAs = g_pImport->EnumGetCount(&hEnum); + } + if(ulCAs || IsPdHasDefault(pPD[j].attr)) + { + char *szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s [%d]",g_szAsmCodeIndent,KEYWORD(".param"),i-ulParams); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),pPD[j].tok); + if(IsPdHasDefault(pPD[j].attr)) DumpDefaultValue(pPD[j].tok, szString, GUICookie); + printLine(GUICookie, szString); + if(ulCAs) + { + while(g_pImport->EnumNext(&hEnum,&tkCA) && RidFromToken(tkCA)) + { + DumpCustomAttribute(tkCA,GUICookie,false); + } + } + } + if(g_fShowCA) g_pImport->EnumClose( &hEnum); + } + } + } +} + +BOOL DumpPermissionSetBlob(void* GUICookie,__inout __nullterminated char* szString, BYTE* pvPermission, ULONG cbPermission) +{ + if(*pvPermission == '.') + { + CQuickBytes out; + pvPermission++; + char* szptr_init = &szString[strlen(szString)]; + char* szptr = szptr_init; + appendStr(&out," = {"); + unsigned nAttrs = CorSigUncompressData((PCCOR_SIGNATURE&)pvPermission); + for(unsigned iAttr = 0; iAttr < nAttrs; iAttr++) + { + unsigned L = CorSigUncompressData((PCCOR_SIGNATURE&)pvPermission); // class name length + mdToken tkAttr = ResolveReflectionNotation(pvPermission,L,g_pImport,GUICookie); + if(IsNilToken(tkAttr)) + { + appendStr(&out,KEYWORD("class ")); + appendStr(&out,"'"); + appendStr(&out,UnquotedProperName((char*)pvPermission,L)); + appendStr(&out,"'"); + } + else + { + PrettyPrintClass(&out, tkAttr, g_pImport); + } + pvPermission += L; + appendStr(&out," = {"); + // dump blob + L = CorSigUncompressData((PCCOR_SIGNATURE&)pvPermission); // blob length + if(L > 0) + { + BYTE* pvEnd = pvPermission+L; + L = CorSigUncompressData((PCCOR_SIGNATURE&)pvPermission); // number of props + if(L > 0) + { + if(!PrettyPrintCustomAttributeNVPairs(L, pvPermission, pvEnd, &out, GUICookie)) + return FALSE; + out.Shrink(out.Size()-1); + } + pvPermission = pvEnd; + } + appendStr(&out, iAttr == nAttrs-1 ? "}" : "}, "); + } + appendStr(&out, "}"); + char* sz = asString(&out); + while(char* pc = strstr(sz,"}, ")) + { + *(pc+2) = 0; + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr), sz); + printLine(GUICookie,szString); + sz = pc+3; + if(szptr == szptr_init) szptr += 4; // to compensate for = { + for(pc = szString; pc < szptr; pc++) *pc = ' '; + } + strcpy_s(szptr, SZSTRING_REMAINING_SIZE(szptr),sz); + return TRUE; + } + return FALSE; +} + +void DumpPermissions(mdToken tkOwner, void* GUICookie) +{ + HCORENUM hEnum = NULL; + static mdPermission rPerm[16384]; + ULONG count; + HRESULT hr; + //static char szString[4096]; + + // can't use internal import here: EnumInit not impl. for mdtPrmission + while (SUCCEEDED(hr = g_pPubImport->EnumPermissionSets( &hEnum, + tkOwner, 0, rPerm, 16384, &count)) && + count > 0) + { + for (ULONG i = 0; i < count; i++) + { + DWORD dwAction; + const BYTE *pvPermission=NULL; + ULONG cbPermission=0; + const char *szAction; + char *szptr; + + szptr = &szString[0]; + if(SUCCEEDED(hr = g_pPubImport->GetPermissionSetProps( rPerm[i], &dwAction, + (const void**)&pvPermission, &cbPermission))) + { + szptr += sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".permissionset")); + switch(dwAction) + { + case dclActionNil: szAction = ""; break; + case dclRequest: szAction = KEYWORD("request"); break; + case dclDemand: szAction = KEYWORD("demand"); break; + case dclAssert: szAction = KEYWORD("assert"); break; + case dclDeny: szAction = KEYWORD("deny"); break; + case dclPermitOnly: szAction = KEYWORD("permitonly"); break; + case dclLinktimeCheck: szAction = KEYWORD("linkcheck"); break; + case dclInheritanceCheck: szAction = KEYWORD("inheritcheck"); break; + case dclRequestMinimum: szAction = KEYWORD("reqmin"); break; + case dclRequestOptional: szAction = KEYWORD("reqopt"); break; + case dclRequestRefuse: szAction = KEYWORD("reqrefuse"); break; + case dclPrejitGrant: szAction = KEYWORD("prejitgrant"); break; + case dclPrejitDenied: szAction = KEYWORD("prejitdeny"); break; + case dclNonCasDemand: szAction = KEYWORD("noncasdemand"); break; + case dclNonCasLinkDemand: szAction = KEYWORD("noncaslinkdemand"); break; + case dclNonCasInheritance: szAction = KEYWORD("noncasinheritance"); break; + default: szAction = ERRORMSG("<UNKNOWN_ACTION>"); break; + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),szAction); + if(pvPermission && cbPermission) + { + printLine(GUICookie, szString); + sprintf_s(szString,SZSTRING_SIZE,"%s ",g_szAsmCodeIndent); + if(!DumpPermissionSetBlob(GUICookie,szString,(BYTE*)pvPermission,cbPermission)) + { + strcat_s(szString,SZSTRING_SIZE,KEYWORD("bytearray")); + strcat_s(szString,SZSTRING_SIZE," ("); + DumpByteArray(szString, pvPermission, cbPermission, GUICookie); + } + printLine(GUICookie,szString); + } + else // i.e. if pvPermission == NULL or cbPermission == NULL + { + sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," = ()"); + printLine(GUICookie,szString); + } + DumpCustomAttributes(rPerm[i],GUICookie); + }// end if(GetPermissionProps) + } // end for(all permissions) + }//end while(EnumPermissionSets) + g_pPubImport->CloseEnum( hEnum); +} + +void PrettyPrintMethodSig(__inout __nullterminated char* szString, unsigned* puStringLen, CQuickBytes* pqbMemberSig, PCCOR_SIGNATURE pComSig, ULONG cComSig, + __inout __nullterminated char* buff, __in_opt __nullterminated char* szArgPrefix, void* GUICookie) +{ + unsigned uMaxWidth = 40; + if(g_fDumpHTML || g_fDumpRTF) uMaxWidth = 240; + if(*buff && (strlen(szString) > (size_t)uMaxWidth)) + { + printLine(GUICookie,szString); + strcpy_s(szString,SZSTRING_SIZE,g_szAsmCodeIndent); + strcat_s(szString,SZSTRING_SIZE," "); // to align with ".method " + } + appendStr(pqbMemberSig, szString); + { + char* pszTailSig = (char*)PrettyPrintSig(pComSig, cComSig, buff, pqbMemberSig, g_pImport, szArgPrefix); + if(*buff) + { + size_t L = strlen(pszTailSig); + char* newbuff = new char[strlen(buff)+3]; + sprintf_s(newbuff,strlen(buff)+3," %s(", buff); + char* pszOffset = strstr(pszTailSig,newbuff); + if(pszOffset) + { + char* pszTailSigRemainder = new char[L+1]; + if(pszOffset - pszTailSig > (int)uMaxWidth) + { + char* pszOffset2 = strstr(pszTailSig," marshal("); + if(pszOffset2 && (pszOffset2 < pszOffset)) + { + *pszOffset2 = 0; + strcpy_s(pszTailSigRemainder,L,pszOffset2+1); + printLine(GUICookie,pszTailSig); + strcpy_s(pszTailSig,L,g_szAsmCodeIndent); + strcat_s(pszTailSig,L," "); // to align with ".method " + strcat_s(pszTailSig,L,pszTailSigRemainder); + pszOffset = strstr(pszTailSig,newbuff); + } + *pszOffset = 0 ; + strcpy_s(pszTailSigRemainder,L,pszOffset+1); + printLine(GUICookie,pszTailSig); + strcpy_s(pszTailSig,L,g_szAsmCodeIndent); + strcat_s(pszTailSig,L," "); // to align with ".method " + strcat_s(pszTailSig,L,pszTailSigRemainder); + pszOffset = strstr(pszTailSig,newbuff); + } + size_t i, j, k, l, indent = pszOffset - pszTailSig + strlen(buff) + 2; + char chAfterComma; + char *pComma = pszTailSig+strlen(buff), *pch; + while((pComma = strchr(pComma,','))) + { + for(pch = pszTailSig, i=0, j = 0, k=0, l=0; pch < pComma; pch++) + { + if(*pch == '\\') pch++; + else + { + if(*pch == '\'') j=1-j; + else if(*pch == '\"') k=1-k; + else if(j==0) + { + if(*pch == '[') i++; + else if(*pch == ']') i--; + else if(strncmp(pch,LTN(),strlen(LTN()))==0) l++; + else if(strncmp(pch,GTN(),strlen(GTN()))==0) l--; + } + } + } + pComma++; + if((i==0)&&(j==0)&&(k==0)&&(l==0))// no brackets/quotes or all opened/closed + { + chAfterComma = *pComma; + strcpy_s(pszTailSigRemainder,L,pComma); + *pComma = 0; + printLine(GUICookie,pszTailSig); + *pComma = chAfterComma; + for(i=0; i<indent; i++) pszTailSig[i] = ' '; + strcpy_s(&pszTailSig[indent],L-indent,pszTailSigRemainder); + pComma = pszTailSig; + } + } + if(*puStringLen < (unsigned)strlen(pszTailSig)+128) + { + //free(szString); + *puStringLen = (unsigned)strlen(pszTailSig)+128; // need additional space for "il managed" etc. + //szString = (char*)malloc(*puStringLen); + } + VDELETE(pszTailSigRemainder); + } + strcpy_s(szString,SZSTRING_SIZE,pszTailSig); + VDELETE(newbuff); + } + else // it's for GUI, don't split it into several lines + { + size_t L = strlen(szString); + if(L < 2048) + { + L = 2048-L; + strncpy_s(szString,SZSTRING_SIZE,pszTailSig,L); + } + } + } +} +// helper to avoid mixing of SEH and stack objects with destructors +BOOL DisassembleWrapper(IMDInternalImport *pImport, BYTE *ILHeader, + void *GUICookie, mdToken FuncToken, ParamDescriptor* pszArgname, ULONG ulArgs) +{ + BOOL fRet = FALSE; + //char szString[4096]; + + WIN_PAL_CPP_TRY + { + fRet = Disassemble(pImport, ILHeader, GUICookie, FuncToken, pszArgname, ulArgs); + } + WIN_PAL_CPP_CATCH_ALL + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_DASMERR),g_szAsmCodeIndent); + printLine(GUICookie, szString); + } + WIN_PAL_CPP_ENDTRY + + return fRet; +} + +BOOL PrettyPrintGP( // prints name of generic param, or returns FALSE + mdToken tkOwner, // Class, method or 0 + CQuickBytes *out, // where to put the pretty printed generic param + int n) // Index of generic param +{ + BOOL ret = FALSE; + if(tkOwner && ((TypeFromToken(tkOwner)==mdtTypeDef)||(TypeFromToken(tkOwner)==mdtMethodDef))) + { + DWORD NumTyPars; + HENUMInternal hEnumTyPar; + + if(SUCCEEDED(g_pImport->EnumInit(mdtGenericParam,tkOwner,&hEnumTyPar))) + { + NumTyPars = g_pImport->EnumGetCount(&hEnumTyPar); + if(NumTyPars > (DWORD)n) + { + // need this for name dup check + LPCSTR *pszName = new LPCSTR[NumTyPars]; + if(pszName != NULL) + { + ULONG ulSequence; + DWORD ix,nx; + mdToken tk; + for(ix = 0, nx = 0xFFFFFFFF; ix < NumTyPars; ix++) + { + if(g_pImport->EnumNext(&hEnumTyPar,&tk)) + { + if(SUCCEEDED(g_pImport->GetGenericParamProps(tk,&ulSequence,NULL,NULL,NULL,&pszName[ix]))) + { + if(ulSequence == (ULONG)n) + nx = ix; + } + } + } + // if there are dup names, use !0 or !!0 + if(nx != 0xFFFFFFFF) + { + for(ix = 0; ix < nx; ix++) + { + if(strcmp(pszName[ix],pszName[nx]) == 0) + break; + } + if(ix >= nx) + { + for(ix = nx+1; ix < NumTyPars; ix++) + { + if(strcmp(pszName[ix],pszName[nx]) == 0) + break; + } + if(ix >= NumTyPars) + { + appendStr(out, ProperName((char*)(pszName[nx]))); + ret = TRUE; + } + } + } // end if(tkTyPar != 0) + delete [] pszName; + } // end if(pszName != NULL) + } // end if(NumTyPars > (DWORD)n) + } // end if(SUCCEEDED(g_pImport->EnumInit(mdtGenericParam,tkOwner,&hEnumTyPar))) + g_pImport->EnumClose(&hEnumTyPar); + } // end if(tkOwner) + return ret; +} + +// Pretty-print formal type parameters for a class or method +char *DumpGenericPars(__inout_ecount(SZSTRING_SIZE) char* szString, mdToken tok, void* GUICookie/*=NULL*/, BOOL fSplit/*=FALSE*/) +{ + WCHAR *wzArgName = wzUniBuf; + ULONG chName; + mdToken tkConstr[2048]; + + DWORD NumTyPars; + DWORD NumConstrs; + mdGenericParam tkTyPar; + DWORD attr; + HCORENUM hEnumTyPar = NULL; + HCORENUM hEnumTyParConstr = NULL; + char* szptr = &szString[strlen(szString)]; + char* szbegin; + unsigned i; + + if (FAILED(g_pPubImport->EnumGenericParams(&hEnumTyPar, tok, &tkTyPar, 1, &NumTyPars))) + return NULL; + if (NumTyPars > 0) + { + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),LTN()); + szbegin = szptr; + + for (i = 1; NumTyPars != 0; i++) + { + g_pPubImport->GetGenericParamProps(tkTyPar, NULL, &attr, NULL, NULL, wzArgName, UNIBUF_SIZE/2, &chName); + //if(wcslen(wzArgName) >= MAX_CLASSNAME_LENGTH) + // wzArgName[MAX_CLASSNAME_LENGTH-1] = 0; + hEnumTyParConstr = NULL; + if (FAILED(g_pPubImport->EnumGenericParamConstraints(&hEnumTyParConstr, tkTyPar, tkConstr, 2048, &NumConstrs))) + { + g_pPubImport->CloseEnum(hEnumTyPar); + return NULL; + } + *szptr = 0; + CHECK_REMAINING_SIZE; + switch (attr & gpVarianceMask) + { + case gpCovariant : szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "+ "); break; + case gpContravariant : szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "- "); break; + } + CHECK_REMAINING_SIZE; + if ((attr & gpReferenceTypeConstraint) != 0) + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "class "); + CHECK_REMAINING_SIZE; + if ((attr & gpNotNullableValueTypeConstraint) != 0) + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "valuetype "); + CHECK_REMAINING_SIZE; + if ((attr & gpDefaultConstructorConstraint) != 0) + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), ".ctor "); + CHECK_REMAINING_SIZE; + if (NumConstrs) + { + CQuickBytes out; + mdToken tkConstrType,tkOwner; + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"("); + DWORD ix; + for (ix=0; ix<NumConstrs; ix++) + { + if (FAILED(g_pPubImport->GetGenericParamConstraintProps(tkConstr[ix], &tkOwner, &tkConstrType))) + return NULL; + + if(ix) szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),", "); + CHECK_REMAINING_SIZE; + out.Shrink(0); + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s",PrettyPrintClass(&out,tkConstrType,g_pImport)); + CHECK_REMAINING_SIZE; + } + if(ix < NumConstrs) break; + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),") "); + CHECK_REMAINING_SIZE; + } + // re-get name, wzUniBuf may not contain it any more + g_pPubImport->GetGenericParamProps(tkTyPar, NULL, &attr, NULL, NULL, wzArgName, UNIBUF_SIZE/2, &chName); + //if(wcslen(wzArgName) >= MAX_CLASSNAME_LENGTH) + // wzArgName[MAX_CLASSNAME_LENGTH-1] = 0; + if (chName) + { + char* sz = (char*)(&wzUniBuf[UNIBUF_SIZE/2]); + WszWideCharToMultiByte(CP_UTF8,0,wzArgName,-1,sz,UNIBUF_SIZE,NULL,NULL); + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s",ProperName(sz)); + } + CHECK_REMAINING_SIZE; + if (FAILED(g_pPubImport->EnumGenericParams(&hEnumTyPar, tok, &tkTyPar, 1, &NumTyPars))) + return NULL; + if (NumTyPars != 0) + { + *szptr++ = ','; + + if(fSplit && (i == 4)) + { + *szptr = 0; + printLine(GUICookie,szString); + i = 0; // mind i++ at the end of the loop + for(szptr = szString; szptr < szbegin; szptr++) *szptr = ' '; + } + } + } // end for (i = 1; NumTyPars != 0; i++) + if(NumTyPars != 0) // all type parameters can't fit in szString, error + { + strcpy_s(szptr,4,"..."); + szptr += 3; + } + else + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),GTN()); + } // end if (NumTyPars > 0) + *szptr = 0; + if(hEnumTyPar) g_pPubImport->CloseEnum(hEnumTyPar); + return szptr; +} + +void DumpGenericParsCA(mdToken tok, void* GUICookie/*=NULL*/) +{ + DWORD NumTyPars; + mdGenericParam tkTyPar; + HCORENUM hEnumTyPar = NULL; + unsigned i; + WCHAR *wzArgName = wzUniBuf; + ULONG chName; + DWORD attr; + + if(g_fShowCA) + { + for(i=0; SUCCEEDED(g_pPubImport->EnumGenericParams(&hEnumTyPar, tok, &tkTyPar, 1, &NumTyPars)) + &&(NumTyPars > 0); i++) + { + HENUMInternal hEnum; + mdCustomAttribute tkCA; + ULONG ulCAs= 0; + + if (FAILED(g_pImport->EnumInit(mdtCustomAttribute, tkTyPar, &hEnum))) + { + sprintf_s(szString, SZSTRING_SIZE, "%sERROR: MetaData error enumerating CustomAttribute for %08X", g_szAsmCodeIndent, tkTyPar); + printLine(GUICookie, szString); + return; + } + ulCAs = g_pImport->EnumGetCount(&hEnum); + if(ulCAs) + { + char *szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".param type")); + if(SUCCEEDED(g_pPubImport->GetGenericParamProps(tkTyPar, NULL, &attr, NULL, NULL, wzArgName, UNIBUF_SIZE/2, &chName)) + &&(chName > 0)) + { + //if(wcslen(wzArgName) >= MAX_CLASSNAME_LENGTH) + // wzArgName[MAX_CLASSNAME_LENGTH-1] = 0; + char* sz = (char*)(&wzUniBuf[UNIBUF_SIZE/2]); + WszWideCharToMultiByte(CP_UTF8,0,wzArgName,-1,sz,UNIBUF_SIZE,NULL,NULL); + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s ",ProperName(sz)); + } + else + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"[%d] ",i+1); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),tkTyPar); + printLine(GUICookie, szString); + while(g_pImport->EnumNext(&hEnum,&tkCA) && RidFromToken(tkCA)) + { + DumpCustomAttribute(tkCA,GUICookie,false); + } + } + g_pImport->EnumClose( &hEnum); + } //end for(i=0;... + } //end if(g_fShowCA) +} + +// Sets *pbOverridingTypeSpec to TRUE if we are overriding a method declared by a type spec. +// In that case the syntax is slightly different (there are additional 'method' keywords). +// Refer to Expert .NET 2.0 IL Assembler page 242. +void PrettyPrintOverrideDecl(ULONG i, __inout __nullterminated char* szString, void* GUICookie, mdToken tkOverrider, + BOOL *pbOverridingTypeSpec) +{ + HRESULT hr; + const char * pszMemberName; + mdToken tkDecl,tkDeclParent=0; + char szBadToken[256]; + char* pszTailSig = ""; + CQuickBytes qbInstSig; + char* szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".override")); + tkDecl = (*g_pmi_list)[i].tkDecl; + + *pbOverridingTypeSpec = FALSE; + + if(g_pImport->IsValidToken(tkDecl)) + { + if(SUCCEEDED(g_pImport->GetParentToken(tkDecl,&tkDeclParent))) + { + if(g_pImport->IsValidToken(tkDeclParent)) + { + if(TypeFromToken(tkDeclParent) == mdtMethodDef) //get the parent's parent + { + mdTypeRef cr1; + if(FAILED(g_pImport->GetParentToken(tkDeclParent,&cr1))) cr1 = mdTypeRefNil; + tkDeclParent = cr1; + } + if(RidFromToken(tkDeclParent)) + { + if(TypeFromToken(tkDeclParent)==mdtTypeSpec) + { + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), " %s ",KEYWORD("method")); + PrettyPrintToken(szString,tkDecl,g_pImport,GUICookie,tkOverrider); + + *pbOverridingTypeSpec = TRUE; + return; + } + PrettyPrintToken(szString, tkDeclParent, g_pImport,GUICookie,tkOverrider); + strcat_s(szString, SZSTRING_SIZE,"::"); + szptr = &szString[strlen(szString)]; + } + } + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s",ERRORMSG("INVALID OVERRIDDEN METHOD'S PARENT TOKEN")); + } + if(TypeFromToken(tkDecl) == mdtMethodSpec) + { + mdToken meth=0; + PCCOR_SIGNATURE pSig=NULL; + ULONG cSig=0; + if (FAILED(g_pImport->GetMethodSpecProps(tkDecl, &meth, &pSig, &cSig))) + { + meth = mdTokenNil; + pSig = NULL; + cSig = 0; + } + + if (pSig && cSig) + { + qbInstSig.Shrink(0); + pszTailSig = (char*)PrettyPrintSig(pSig, cSig, "", &qbInstSig, g_pImport, NULL); + } + tkDecl = meth; + } + if(TypeFromToken(tkDecl) == mdtMethodDef) + { + if (FAILED(g_pImport->GetNameOfMethodDef(tkDecl, &pszMemberName))) + { + sprintf_s(szBadToken,256,ERRORMSG("INVALID RECORD: 0x%8.8X"),tkDecl); + pszMemberName = (const char *)szBadToken; + } + } + else if(TypeFromToken(tkDecl) == mdtMemberRef) + { + PCCOR_SIGNATURE pComSig; + ULONG cComSig; + + if (FAILED(g_pImport->GetNameAndSigOfMemberRef( + tkDecl, + &pComSig, + &cComSig, + &pszMemberName))) + { + sprintf_s(szBadToken,256,ERRORMSG("INVALID RECORD: 0x%8.8X"),tkDecl); + pszMemberName = (const char *)szBadToken; + } + } + else + { + sprintf_s(szBadToken,256,ERRORMSG("INVALID TOKEN: 0x%8.8X"),tkDecl); + pszMemberName = (const char*)szBadToken; + } + MAKE_NAME_IF_NONE(pszMemberName,tkDecl); + } + else + { + sprintf_s(szBadToken,256,ERRORMSG("INVALID TOKEN: 0x%8.8X"),tkDecl); + pszMemberName = (const char*)szBadToken; + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%s",ProperName((char*)pszMemberName),pszTailSig); + + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(" /*%08X::%08X*/ "),tkDeclParent,(*g_pmi_list)[i].tkDecl); +} + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +BOOL DumpMethod(mdToken FuncToken, const char *pszClassName, DWORD dwEntryPointToken,void *GUICookie,BOOL DumpBody) +{ + HRESULT hr; + const char *pszMemberName = NULL;//[MAX_MEMBER_LENGTH]; + const char *pszMemberSig = NULL; + DWORD dwAttrs = 0; + DWORD dwImplAttrs; + DWORD dwOffset; + DWORD dwTargetRVA; + CQuickBytes qbMemberSig; + PCCOR_SIGNATURE pComSig = NULL; + ULONG cComSig; + char *buff = NULL;//[MAX_MEMBER_LENGTH]; + ParamDescriptor* pszArgname = NULL; + ULONG ulArgs=0; + unsigned retParamIx = 0; + unsigned uStringLen = SZSTRING_SIZE; + char szArgPrefix[32]; + char* szptr = NULL; + mdToken tkMVarOwner = g_tkMVarOwner; + + if (FAILED(g_pImport->GetMethodDefProps(FuncToken, &dwAttrs))) + { + sprintf_s(szString, SZSTRING_SIZE, "%sERROR: MethodDef %08X has wrong record", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, ERRORMSG(szString)); + return FALSE; + } + if (g_fLimitedVisibility) + { + if(g_fHidePub && IsMdPublic(dwAttrs)) return FALSE; + if(g_fHidePriv && IsMdPrivate(dwAttrs)) return FALSE; + if(g_fHideFam && IsMdFamily(dwAttrs)) return FALSE; + if(g_fHideAsm && IsMdAssem(dwAttrs)) return FALSE; + if(g_fHideFOA && IsMdFamORAssem(dwAttrs)) return FALSE; + if(g_fHideFAA && IsMdFamANDAssem(dwAttrs)) return FALSE; + if(g_fHidePrivScope && IsMdPrivateScope(dwAttrs)) return FALSE; + } + if (FAILED(g_pImport->GetMethodImplProps(FuncToken, &dwOffset, &dwImplAttrs))) + { + sprintf_s(szString, SZSTRING_SIZE, "%sERROR: Invalid MethodImpl %08X record", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, ERRORMSG(szString)); + return FALSE; + } + if (FAILED(g_pImport->GetNameOfMethodDef(FuncToken, &pszMemberName))) + { + sprintf_s(szString, SZSTRING_SIZE, "%sERROR: MethodDef %08X has wrong record", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, ERRORMSG(szString)); + return FALSE; + } + MAKE_NAME_IF_NONE(pszMemberName,FuncToken); + if (FAILED(g_pImport->GetSigOfMethodDef(FuncToken, &cComSig, &pComSig))) + { + pComSig = NULL; + } + + if (cComSig == NULL) + { + sprintf_s(szString, SZSTRING_SIZE, "%sERROR: method '%s' has no signature", g_szAsmCodeIndent, pszMemberName); + printError(GUICookie, ERRORMSG(szString)); + return FALSE; + } + bool bRet = FALSE; + + WIN_PAL_CPP_TRY { + if((*pComSig & IMAGE_CEE_CS_CALLCONV_MASK) > IMAGE_CEE_CS_CALLCONV_VARARG) + { + sprintf_s(szString,SZSTRING_SIZE,"%sERROR: signature of method '%s' has invalid calling convention 0x%2.2X",g_szAsmCodeIndent,pszMemberName,*pComSig); + printError(GUICookie,ERRORMSG(szString)); + bRet = TRUE; + goto lDone; + } + + g_tkMVarOwner = FuncToken; + szString[0] = 0; + DumpGenericPars(szString,FuncToken); //,NULL,FALSE); + pszMemberSig = PrettyPrintSig(pComSig, cComSig, szString, &qbMemberSig, g_pImport,NULL); +lDone: ; + } WIN_PAL_CPP_CATCH_ALL { + printError(GUICookie,"INVALID DATA ADDRESS"); + bRet = TRUE; + } WIN_PAL_CPP_ENDTRY; + + if (bRet) + { + g_tkMVarOwner = tkMVarOwner; + return FALSE; + } + + if (g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + if (strcmp(pszMemberName, g_pszMethodToDump) != 0) return FALSE; + + if (g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + // we want plain signature without token values + const char *pszPlainSig; + if (g_fDumpTokens) + { + // temporarily disable token dumping + g_fDumpTokens = FALSE; + + WIN_PAL_CPP_TRY + { + CQuickBytes qbTempSig; + pszPlainSig = PrettyPrintSig(pComSig, cComSig, "", &qbTempSig, g_pImport, NULL); + } + WIN_PAL_CPP_CATCH_ALL + { + pszPlainSig = ""; + } + WIN_PAL_CPP_ENDTRY; + + g_fDumpTokens = TRUE; + } + else + { + pszPlainSig = pszMemberSig; + } + + if (strcmp(pszPlainSig, g_pszSigToDump) != 0) return FALSE; + } + } + + if(!DumpBody) + { + printLine(GUICookie,(char*)pszMemberSig); + g_tkMVarOwner = tkMVarOwner; + return TRUE; + } + + szptr = &szString[0]; + szString[0] = 0; + if(DumpBody) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%s ",g_szAsmCodeIndent,ANCHORPT(KEYWORD(".method"),FuncToken)); + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s ",ANCHORPT(KEYWORD(".method"),FuncToken)); + + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),FuncToken); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)0)); + if(IsMdPublic(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"public "); + if(IsMdPrivate(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"private "); + if(IsMdFamily(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"family "); + if(IsMdAssem(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"assembly "); + if(IsMdFamANDAssem(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"famandassem "); + if(IsMdFamORAssem(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"famorassem "); + if(IsMdPrivateScope(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"privatescope "); + if(IsMdHideBySig(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"hidebysig "); + if(IsMdNewSlot(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"newslot "); + if(IsMdSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"specialname "); + if(IsMdRTSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"rtspecialname "); + if (IsMdStatic(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"static "); + if (IsMdAbstract(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"abstract "); + if (dwAttrs & 0x00000200) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"strict "); + if (IsMdVirtual(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"virtual "); + if (IsMdFinal(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"final "); + if (IsMdUnmanagedExport(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"unmanagedexp "); + if(IsMdRequireSecObject(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"reqsecobj "); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)-1)); + if (IsMdPinvokeImpl(dwAttrs)) + { + DWORD dwMappingFlags; + const char *szImportName; + mdModuleRef mrImportDLL; + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s(",KEYWORD("pinvokeimpl")); + if(FAILED(g_pImport->GetPinvokeMap(FuncToken,&dwMappingFlags, + &szImportName,&mrImportDLL))) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/* No map */")); + else + szptr=DumpPinvokeMap(dwMappingFlags, (strcmp(szImportName,pszMemberName)? szImportName : NULL), + mrImportDLL,szString,GUICookie); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),") "); + } + // A little hack to get the formatting we need for Assem. + buff = new char[SZSTRING_SIZE]; + if(buff==NULL) + { + printError(GUICookie,"Out of memory"); + g_tkMVarOwner = tkMVarOwner; + return FALSE; + } + g_fThisIsInstanceMethod = !IsMdStatic(dwAttrs); + { + const char *psz = NULL; + if(IsMdPrivateScope(dwAttrs)) + sprintf_s(buff,SZSTRING_SIZE,"%s$PST%08X", pszMemberName,FuncToken ); + else + strcpy_s(buff,SZSTRING_SIZE, pszMemberName ); + + psz = ProperName(buff); + if(psz != buff) + { + strcpy_s(buff,SZSTRING_SIZE,psz); + } + } + + DumpGenericPars(buff, FuncToken); //, NULL, FALSE); + + qbMemberSig.Shrink(0); + // Get the argument names, if any + strcpy_s(szArgPrefix,32,(g_fThisIsInstanceMethod ? "A1": "A0")); + { + PCCOR_SIGNATURE typePtr = pComSig; + unsigned ulCallConv = CorSigUncompressData(typePtr); // get the calling convention out of the way + if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) + CorSigUncompressData(typePtr); // get the num of generic args out of the way + unsigned numArgs = CorSigUncompressData(typePtr)+1; + HENUMInternal hArgEnum; + mdParamDef tkArg; + if (FAILED(g_pImport->EnumInit(mdtParamDef,FuncToken,&hArgEnum))) + { + printError(GUICookie, "Invalid MetaDataFormat"); + g_tkMVarOwner = tkMVarOwner; + return FALSE; + } + ulArgs = g_pImport->EnumGetCount(&hArgEnum); + retParamIx = numArgs-1; + if (ulArgs < numArgs) ulArgs = numArgs; + if (ulArgs != 0) + { + pszArgname = new ParamDescriptor[ulArgs+2]; + memset(pszArgname,0,(ulArgs+2)*sizeof(ParamDescriptor)); + LPCSTR szName; + ULONG ulSequence, ix; + USHORT wSequence; + DWORD dwAttr; + ULONG j; + for (j=0; g_pImport->EnumNext(&hArgEnum,&tkArg) && RidFromToken(tkArg); j++) + { + if (FAILED(g_pImport->GetParamDefProps(tkArg, &wSequence, &dwAttr, &szName))) + { + char sz[256]; + sprintf_s(sz, COUNTOF(sz), RstrUTF(IDS_E_INVALIDRECORD), tkArg); + printError(GUICookie, sz); + continue; + } + ulSequence = wSequence; + + if (ulSequence > ulArgs+1) + { + char sz[256]; + sprintf_s(sz,256,RstrUTF(IDS_E_PARAMSEQNO),j,ulSequence,ulSequence); + printError(GUICookie,sz); + } + else + { + ix = retParamIx; + if (ulSequence != 0) + { + ix = ulSequence-1; + if (*szName != 0) + { + pszArgname[ix].name = new char[strlen(szName)+1]; + strcpy_s(pszArgname[ix].name,strlen(szName)+1,szName); + } + } + pszArgname[ix].attr = dwAttr; + pszArgname[ix].tok = tkArg; + } + }// end for( along the params) + for (j=0; j <numArgs; j++) + { + if(pszArgname[j].name == NULL) // we haven't got the name! + { + pszArgname[j].name = new char[16]; + *pszArgname[j].name = 0; + } + if(*pszArgname[j].name == 0) // we haven't got the name! + { + sprintf_s(pszArgname[j].name,16,"A_%d",g_fThisIsInstanceMethod ? j+1 : j); + } + }// end for( along the argnames) +#ifdef _WIN64 + sprintf_s(szArgPrefix,32,"@%I64d0",(size_t)pszArgname); +#else + sprintf_s(szArgPrefix,32,"@%d0",(size_t)pszArgname); +#endif //_WIN64 + } //end if (ulArgs) + g_pImport->EnumClose(&hArgEnum); + } + g_tkRefUser = FuncToken; + PrettyPrintMethodSig(szString, &uStringLen, &qbMemberSig, pComSig, cComSig, + buff, szArgPrefix, GUICookie); + g_tkRefUser = 0; + szptr = &szString[strlen(szString)]; + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)0)); + if(IsMiNative(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," native"); + if(IsMiIL(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," cil"); + if(IsMiOPTIL(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," optil"); + if(IsMiRuntime(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," runtime"); + if(IsMiUnmanaged(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," unmanaged"); + if(IsMiManaged(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," managed"); + if(IsMiPreserveSig(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," preservesig"); + if(IsMiForwardRef(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," forwardref"); + if(IsMiInternalCall(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," internalcall"); + if(IsMiSynchronized(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," synchronized"); + if(IsMiNoInlining(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," noinlining"); + if(IsMiAggressiveInlining(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," aggressiveinlining"); + if(IsMiNoOptimization(dwImplAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," nooptimization"); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)-1)); + printLine(GUICookie, szString); + VDELETE(buff); + + if(!DumpBody) + { + g_tkMVarOwner = tkMVarOwner; + return TRUE; + } + + if(g_fShowBytes) + { + if (FAILED(g_pImport->GetSigOfMethodDef(FuncToken, &cComSig, &pComSig))) + { + sprintf_s(szString,SZSTRING_SIZE,"%sERROR: method %08X has wrong record",g_szAsmCodeIndent,FuncToken); + printError(GUICookie,ERRORMSG(szString)); + return FALSE; + } + char* szt = "SIG:"; + for(ULONG i=0; i<cComSig;) + { + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s// %s", g_szAsmCodeIndent, szt); + while(i<cComSig) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %02X",pComSig[i]); + i++; + if((i & 0x1F)==0) break; // print only 32 per line + } + printLine(GUICookie, COMMENT(szString)); + szt = " "; + } + } + + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s", g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie, szString); + szptr = &szString[0]; + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + + // We have recoreded the entry point token from the CLR Header. Check to see if this + // method is the entry point. + if(FuncToken == static_cast<mdToken>(dwEntryPointToken)) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s", g_szAsmCodeIndent,KEYWORD(".entrypoint")); + printLine(GUICookie, szString); + } + DumpCustomAttributes(FuncToken,GUICookie); + DumpGenericParsCA(FuncToken,GUICookie); + DumpParams(pszArgname, retParamIx, GUICookie); + DumpPermissions(FuncToken,GUICookie); + // Check if the method represents entry in VTable fixups and in EATable + { + ULONG j; + for(j=0; j<g_nVTableRef; j++) + { + if((*g_prVTableRef)[j].tkTok == FuncToken) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s %d : %d", + g_szAsmCodeIndent,KEYWORD(".vtentry"),(*g_prVTableRef)[j].wEntry+1,(*g_prVTableRef)[j].wSlot+1); + printLine(GUICookie, szString); + break; + } + } + for(j=0; j<g_nEATableRef; j++) + { + if((*g_prEATableRef)[j].tkTok == FuncToken) + { + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s [%d] ", + g_szAsmCodeIndent,KEYWORD(".export"),j+g_nEATableBase); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s %s", + KEYWORD("as"), ProperName((*g_prEATableRef)[j].pszName)); + printLine(GUICookie, szString); + break; + } + } + } + // Dump method impls of this method: + for(ULONG i = 0; i < g_NumMI; i++) + { + if((*g_pmi_list)[i].tkBody == FuncToken) + { + BOOL bOverridingTypeSpec; + PrettyPrintOverrideDecl(i,szString,GUICookie,FuncToken,&bOverridingTypeSpec); + printLine(GUICookie,szString); + } + } + dwTargetRVA = dwOffset; + if (IsMdPinvokeImpl(dwAttrs)) + { + if(dwOffset) + { + sprintf_s(szString,SZSTRING_SIZE,"%s// Embedded native code",g_szAsmCodeIndent); + printLine(GUICookie, COMMENT(szString)); + goto ItsMiNative; + } + if(g_szAsmCodeIndent[0]) g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie, szString); + g_tkMVarOwner = tkMVarOwner; + return TRUE; + } + + if(IsMiManaged(dwImplAttrs)) + { + if(IsMiIL(dwImplAttrs) || IsMiOPTIL(dwImplAttrs)) + { + if(g_fShowBytes) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_METHBEG), g_szAsmCodeIndent,dwTargetRVA); + printLine(GUICookie, COMMENT(szString)); + } + szString[0] = 0; + if (dwTargetRVA != 0) + { + void* newTarget; + if(g_pPELoader->getVAforRVA(dwTargetRVA,&newTarget)) + { + DisassembleWrapper(g_pImport, (unsigned char*)newTarget, GUICookie, FuncToken,pszArgname, ulArgs); + } + else + { + sprintf_s(szString,SZSTRING_SIZE, "INVALID METHOD ADDRESS: 0x%8.8X (RVA: 0x%8.8X)",(size_t)newTarget,dwTargetRVA); + printError(GUICookie,szString); + } + } + } + else if(IsMiNative(dwImplAttrs)) + { +ItsMiNative: + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_DASMNATIVE), g_szAsmCodeIndent); + printLine(GUICookie, COMMENT(szString)); + + sprintf_s(szString,SZSTRING_SIZE,"%s// Managed TargetRVA = 0x%8.8X", g_szAsmCodeIndent, dwTargetRVA); + printLine(GUICookie, COMMENT(szString)); + } + } + else if(IsMiUnmanaged(dwImplAttrs)&&IsMiNative(dwImplAttrs)) + { + _ASSERTE(IsMiNative(dwImplAttrs)); + sprintf_s(szString,SZSTRING_SIZE,"%s// Unmanaged TargetRVA = 0x%8.8X", g_szAsmCodeIndent, dwTargetRVA); + printLine(GUICookie, COMMENT(szString)); + } + else if(IsMiRuntime(dwImplAttrs)) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_METHODRT), g_szAsmCodeIndent); + printLine(GUICookie, COMMENT(szString)); + } +#ifdef _DEBUG + else _ASSERTE(!"Bad dwImplAttrs"); +#endif + + if(g_szAsmCodeIndent[0]) g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + { + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,UNSCOPE()); + if(pszClassName) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// end of method %s::"), ProperName((char*)pszClassName)); + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(ProperName((char*)pszMemberName))); + } + else + sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// end of global method %s"), ProperName((char*)pszMemberName)); + } + printLine(GUICookie, szString); + szString[0] = 0; + printLine(GUICookie, szString); + + if(pszArgname) + { + for(ULONG i=0; i < ulArgs; i++) + { + if(pszArgname[i].name) VDELETE(pszArgname[i].name); + } + VDELETE(pszArgname); + } + g_tkMVarOwner = tkMVarOwner; + return TRUE; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +BOOL DumpField(mdToken FuncToken, const char *pszClassName,void *GUICookie, BOOL DumpBody) +{ + char *pszMemberName = NULL;//[MAX_MEMBER_LENGTH]; + DWORD dwAttrs = 0; + CQuickBytes qbMemberSig; + PCCOR_SIGNATURE pComSig = NULL; + ULONG cComSig; + const char *szStr = NULL;//[1024]; + char* szptr; + + const char *psz; + if (FAILED(g_pImport->GetNameOfFieldDef(FuncToken, &psz))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: FieldDef %08X has no signature", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, sz); + return FALSE; + } + MAKE_NAME_IF_NONE(psz,FuncToken); + + if (FAILED(g_pImport->GetFieldDefProps(FuncToken, &dwAttrs))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: FieldDef %08X record error", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, sz); + return FALSE; + } + if (g_fLimitedVisibility) + { + if(g_fHidePub && IsFdPublic(dwAttrs)) return FALSE; + if(g_fHidePriv && IsFdPrivate(dwAttrs)) return FALSE; + if(g_fHideFam && IsFdFamily(dwAttrs)) return FALSE; + if(g_fHideAsm && IsFdAssembly(dwAttrs)) return FALSE; + if(g_fHideFOA && IsFdFamORAssem(dwAttrs)) return FALSE; + if(g_fHideFAA && IsFdFamANDAssem(dwAttrs)) return FALSE; + if(g_fHidePrivScope && IsFdPrivateScope(dwAttrs)) return FALSE; + } + + { + const char* psz1 = NULL; + if(IsFdPrivateScope(dwAttrs)) + { + pszMemberName = new char[strlen(psz)+15]; + sprintf_s(pszMemberName,strlen(psz)+15,"%s$PST%08X", psz,FuncToken ); + } + else + { + pszMemberName = new char[strlen(psz)+3]; + strcpy_s(pszMemberName, strlen(psz)+3, psz ); + } + psz1 = ProperName(pszMemberName); + VDELETE(pszMemberName); + pszMemberName = new char[strlen(psz1)+1]; + strcpy_s(pszMemberName,strlen(psz1)+1,psz1); + } + if (FAILED(g_pImport->GetSigOfFieldDef(FuncToken, &cComSig, &pComSig))) + { + pComSig = NULL; + } + if (cComSig == NULL) + { + char sz[2048]; + sprintf_s(sz,2048,"%sERROR: field '%s' has no signature",g_szAsmCodeIndent,pszMemberName); + VDELETE(pszMemberName); + printError(GUICookie,sz); + return FALSE; + } + g_tkRefUser = FuncToken; + + bool bRet = FALSE; + WIN_PAL_CPP_TRY { + szStr = PrettyPrintSig(pComSig, cComSig, (DumpBody ? pszMemberName : ""), &qbMemberSig, g_pImport,NULL); + } + WIN_PAL_CPP_CATCH_ALL + { + printError(GUICookie,"INVALID ADDRESS IN FIELD SIGNATURE"); + bRet = TRUE; + } WIN_PAL_CPP_ENDTRY; + + if (bRet) + return FALSE; + + g_tkRefUser = 0; + + if (g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + if (strcmp(pszMemberName, g_pszMethodToDump) != 0) + { + VDELETE(pszMemberName); + return FALSE; + } + + if (g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + // we want plain signature without token values and without the field name + BOOL fDumpTokens = g_fDumpTokens; + g_fDumpTokens = FALSE; + + const char *pszPlainSig; + WIN_PAL_CPP_TRY + { + CQuickBytes qbTempSig; + pszPlainSig = PrettyPrintSig(pComSig, cComSig, "", &qbTempSig, g_pImport, NULL); + } + WIN_PAL_CPP_CATCH_ALL + { + pszPlainSig = ""; + } + WIN_PAL_CPP_ENDTRY; + + g_fDumpTokens = fDumpTokens; + + if (strcmp(pszPlainSig, g_pszSigToDump) != 0) + { + VDELETE(pszMemberName); + return FALSE; + } + } + } + VDELETE(pszMemberName); + + szptr = &szString[0]; + if(DumpBody) + { + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ", g_szAsmCodeIndent,ANCHORPT(KEYWORD(".field"),FuncToken)); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),FuncToken); + } + + // put offset (if any) + for(ULONG i=0; i < g_cFieldOffsets; i++) + { + if(g_rFieldOffset[i].ridOfField == FuncToken) + { + if(g_rFieldOffset[i].ulOffset != 0xFFFFFFFF) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"[%d] ",g_rFieldOffset[i].ulOffset); + break; + } + } + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)0)); + if(IsFdPublic(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"public "); + if(IsFdPrivate(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"private "); + if(IsFdStatic(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"static "); + if(IsFdFamily(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"family "); + if(IsFdAssembly(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"assembly "); + if(IsFdFamANDAssem(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"famandassem "); + if(IsFdFamORAssem(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"famorassem "); + if(IsFdPrivateScope(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"privatescope "); + if(IsFdInitOnly(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"initonly "); + if(IsFdLiteral(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"literal "); + if(IsFdNotSerialized(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"notserialized "); + if(IsFdSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"specialname "); + if(IsFdRTSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"rtspecialname "); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)-1)); + if (IsFdPinvokeImpl(dwAttrs)) + { + DWORD dwMappingFlags; + const char *szImportName; + mdModuleRef mrImportDLL; + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s(",KEYWORD("pinvokeimpl")); + if(FAILED(g_pImport->GetPinvokeMap(FuncToken,&dwMappingFlags, + &szImportName,&mrImportDLL))) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/* No map */")); + else + szptr = DumpPinvokeMap(dwMappingFlags, (strcmp(szImportName,psz)? szImportName : NULL), + mrImportDLL, szString,GUICookie); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),") "); + } + szptr = DumpMarshaling(g_pImport,szString,SZSTRING_SIZE,FuncToken); + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s",szStr); + + if (IsFdHasFieldRVA(dwAttrs)) // Do we have an RVA associated with this? + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), KEYWORD(" at ")); + + ULONG fieldRVA; + if (SUCCEEDED(g_pImport->GetFieldRVA(FuncToken, &fieldRVA))) + { + szptr = DumpDataPtr(&szString[strlen(szString)], fieldRVA, SizeOfField(FuncToken,g_pImport)); + } + else + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),RstrUTF(IDS_E_NORVA)); + } + } + + // dump default value (if any): + if(IsFdHasDefault(dwAttrs) && DumpBody) DumpDefaultValue(FuncToken,szString,GUICookie); + printLine(GUICookie, szString); + + if(DumpBody) + { + DumpCustomAttributes(FuncToken,GUICookie); + DumpPermissions(FuncToken,GUICookie); + } + + return TRUE; + +} + +BOOL DumpEvent(mdToken FuncToken, const char *pszClassName, DWORD dwClassAttrs, void *GUICookie, BOOL DumpBody) +{ + DWORD dwAttrs; + mdToken tkEventType; + LPCSTR psz; + HENUMInternal hAssoc; + ASSOCIATE_RECORD rAssoc[128]; + CQuickBytes qbMemberSig; + ULONG nAssoc; + char* szptr; + + if (FAILED(g_pImport->GetEventProps(FuncToken,&psz,&dwAttrs,&tkEventType))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: Invalid Event %08X record", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, sz); + return FALSE; + } + MAKE_NAME_IF_NONE(psz,FuncToken); + if (g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + if (strcmp(psz, g_pszMethodToDump) != 0) return FALSE; + } + + if (FAILED(g_pImport->EnumAssociateInit(FuncToken,&hAssoc))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: MetaData error enumerating Associate for %08X", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, sz); + return FALSE; + } + + if ((nAssoc = hAssoc.m_ulCount)) + { + memset(rAssoc,0,sizeof(rAssoc)); + if (FAILED(g_pImport->GetAllAssociates(&hAssoc,rAssoc,nAssoc))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: MetaData error enumerating all Associates", g_szAsmCodeIndent); + printError(GUICookie, sz); + return FALSE; + } + + if (g_fLimitedVisibility) + { + unsigned i; + for (i=0; i < nAssoc;i++) + { + if ((TypeFromToken(rAssoc[i].m_memberdef) == mdtMethodDef) && g_pImport->IsValidToken(rAssoc[i].m_memberdef)) + { + DWORD dwMethodAttrs; + if (FAILED(g_pImport->GetMethodDefProps(rAssoc[i].m_memberdef, &dwMethodAttrs))) + { + continue; + } + if(g_fHidePub && IsMdPublic(dwMethodAttrs)) continue; + if(g_fHidePriv && IsMdPrivate(dwMethodAttrs)) continue; + if(g_fHideFam && IsMdFamily(dwMethodAttrs)) continue; + if(g_fHideAsm && IsMdAssem(dwMethodAttrs)) continue; + if(g_fHideFOA && IsMdFamORAssem(dwMethodAttrs)) continue; + if(g_fHideFAA && IsMdFamANDAssem(dwMethodAttrs)) continue; + if(g_fHidePrivScope && IsMdPrivateScope(dwMethodAttrs)) continue; + break; + } + } + if (i >= nAssoc) return FALSE; + } + } + + szptr = &szString[0]; + if (DumpBody) + { + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ", g_szAsmCodeIndent,KEYWORD(".event")); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),FuncToken); + } + else + { + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s : ",ProperName((char*)psz)); + } + + if(IsEvSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("specialname ")); + if(IsEvRTSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("rtspecialname ")); + + if(RidFromToken(tkEventType)&&g_pImport->IsValidToken(tkEventType)) + { + switch(TypeFromToken(tkEventType)) + { + case mdtTypeRef: + case mdtTypeDef: + case mdtTypeSpec: + { + PrettyPrintToken(szString, tkEventType, g_pImport,GUICookie,0); + szptr = &szString[strlen(szString)]; + } + break; + default: + break; + } + } + + if(!DumpBody) + { + printLine(GUICookie,szString); + return TRUE; + } + + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %s", ProperName((char*)psz)); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + + DumpCustomAttributes(FuncToken,GUICookie); + DumpPermissions(FuncToken,GUICookie); + + if(nAssoc) + { + for(unsigned i=0; i < nAssoc;i++) + { + mdToken tk = rAssoc[i].m_memberdef; + DWORD sem = rAssoc[i].m_dwSemantics; + + szptr = &szString[0]; + if(IsMsAddOn(sem)) szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".addon")); + else if(IsMsRemoveOn(sem)) szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".removeon")); + else if(IsMsFire(sem)) szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".fire")); + else if(IsMsOther(sem)) szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".other")); + else szptr+=sprintf_s(szptr,SZSTRING_SIZE,ERRORMSG("UNKNOWN SEMANTICS: 0x%X "),sem); + + if(g_pImport->IsValidToken(tk)) + PrettyPrintToken(szString, tk, g_pImport,GUICookie,0); + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG("INVALID TOKEN 0x%8.8X"),tk); + printLine(GUICookie,szString); + } + } + if(g_szAsmCodeIndent[0]) g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,UNSCOPE()); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// end of event %s::"),ProperName((char*)pszClassName)); + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(ProperName((char*)psz))); + printLine(GUICookie,szString); + return TRUE; + +} + +BOOL DumpProp(mdToken FuncToken, const char *pszClassName, DWORD dwClassAttrs, void *GUICookie, BOOL DumpBody) +{ + DWORD dwAttrs; + LPCSTR psz; + HENUMInternal hAssoc; + ASSOCIATE_RECORD rAssoc[128]; + CQuickBytes qbMemberSig; + PCCOR_SIGNATURE pComSig; + ULONG cComSig, nAssoc; + unsigned uStringLen = SZSTRING_SIZE; + char* szptr; + + if (FAILED(g_pImport->GetPropertyProps(FuncToken,&psz,&dwAttrs,&pComSig,&cComSig))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: Invalid Property %08X record", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, sz); + return FALSE; + } + MAKE_NAME_IF_NONE(psz,FuncToken); + if(cComSig == 0) + { + char sz[2048]; + sprintf_s(sz,2048,"%sERROR: property '%s' has no signature",g_szAsmCodeIndent,psz); + printError(GUICookie,sz); + return FALSE; + } + + if (g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + if (strcmp(psz, g_pszMethodToDump) != 0) return FALSE; + } + + if (FAILED(g_pImport->EnumAssociateInit(FuncToken,&hAssoc))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: MetaData error enumerating Associate for %08X", g_szAsmCodeIndent, FuncToken); + printError(GUICookie, sz); + return FALSE; + } + if ((nAssoc = hAssoc.m_ulCount) != 0) + { + memset(rAssoc,0,sizeof(rAssoc)); + if (FAILED(g_pImport->GetAllAssociates(&hAssoc,rAssoc,nAssoc))) + { + char sz[2048]; + sprintf_s(sz, 2048, "%sERROR: MetaData error enumerating all Associates", g_szAsmCodeIndent); + printError(GUICookie, sz); + return FALSE; + } + + if (g_fLimitedVisibility) + { + unsigned i; + for (i=0; i < nAssoc;i++) + { + if ((TypeFromToken(rAssoc[i].m_memberdef) == mdtMethodDef) && g_pImport->IsValidToken(rAssoc[i].m_memberdef)) + { + DWORD dwMethodAttrs; + if (FAILED(g_pImport->GetMethodDefProps(rAssoc[i].m_memberdef, &dwMethodAttrs))) + { + continue; + } + if(g_fHidePub && IsMdPublic(dwMethodAttrs)) continue; + if(g_fHidePriv && IsMdPrivate(dwMethodAttrs)) continue; + if(g_fHideFam && IsMdFamily(dwMethodAttrs)) continue; + if(g_fHideAsm && IsMdAssem(dwMethodAttrs)) continue; + if(g_fHideFOA && IsMdFamORAssem(dwMethodAttrs)) continue; + if(g_fHideFAA && IsMdFamANDAssem(dwMethodAttrs)) continue; + if(g_fHidePrivScope && IsMdPrivateScope(dwMethodAttrs)) continue; + break; + } + } + if( i >= nAssoc) return FALSE; + } + } + + szptr = &szString[0]; + if (DumpBody) + { + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ", g_szAsmCodeIndent,KEYWORD(".property")); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),FuncToken); + } + else + { + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s : ",ProperName((char*)psz)); + } + + if(IsPrSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("specialname ")); + if(IsPrRTSpecialName(dwAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("rtspecialname ")); + + { + char *pch = ""; + if(DumpBody) + { + pch = szptr+1; + strcpy_s(pch,SZSTRING_REMAINING_SIZE(szptr),ProperName((char*)psz)); + } + qbMemberSig.Shrink(0); + PrettyPrintMethodSig(szString, &uStringLen, &qbMemberSig, pComSig, cComSig, + pch, NULL, GUICookie); + if(IsPrHasDefault(dwAttrs) && DumpBody) DumpDefaultValue(FuncToken,szString,GUICookie); + } + printLine(GUICookie,szString); + + if(DumpBody) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + + DumpCustomAttributes(FuncToken,GUICookie); + DumpPermissions(FuncToken,GUICookie); + + if(nAssoc) + { + for(unsigned i=0; i < nAssoc;i++) + { + mdToken tk = rAssoc[i].m_memberdef; + DWORD sem = rAssoc[i].m_dwSemantics; + + szptr = &szString[0]; + if(IsMsSetter(sem)) szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".set")); + else if(IsMsGetter(sem)) szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".get")); + else if(IsMsOther(sem)) szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".other")); + else szptr+=sprintf_s(szptr,SZSTRING_SIZE,ERRORMSG("UNKNOWN SEMANTICS: 0x%X "),sem); + + if(g_pImport->IsValidToken(tk)) + PrettyPrintToken(szString, tk, g_pImport,GUICookie,0); + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG("INVALID TOKEN 0x%8.8X"),tk); + printLine(GUICookie,szString); + } + } + if(g_szAsmCodeIndent[0]) g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,UNSCOPE()); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// end of property %s::"),ProperName((char*)pszClassName)); + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(ProperName((char*)psz))); + printLine(GUICookie,szString); + } // end if(DumpBody) + return TRUE; + +} + +BOOL DumpMembers(mdTypeDef cl, const char *pszClassNamespace, const char *pszClassName, + DWORD dwClassAttrs, DWORD dwEntryPointToken, void* GUICookie) +{ + HRESULT hr; + mdToken *pMemberList = NULL; + DWORD NumMembers, NumFields,NumMethods,NumEvents,NumProps; + DWORD i; + HENUMInternal hEnumMethod; + HENUMInternal hEnumField; + HENUMInternal hEnumEvent; + HENUMInternal hEnumProp; + CQuickBytes qbMemberSig; + BOOL ret; + + // Get the total count of methods + fields + hr = g_pImport->EnumInit(mdtMethodDef, cl, &hEnumMethod); + if (FAILED(hr)) + { +FailedToEnum: + printLine(GUICookie,RstrUTF(IDS_E_MEMBRENUM)); + ret = FALSE; + goto CloseHandlesAndReturn; + } + NumMembers = NumMethods = g_pImport->EnumGetCount(&hEnumMethod); + + + if (FAILED(g_pImport->EnumInit(mdtFieldDef, cl, &hEnumField))) goto FailedToEnum; + NumFields = g_pImport->EnumGetCount(&hEnumField); + NumMembers += NumFields; + + if (FAILED(g_pImport->EnumInit(mdtEvent, cl, &hEnumEvent))) goto FailedToEnum; + NumEvents = g_pImport->EnumGetCount(&hEnumEvent); + NumMembers += NumEvents; + + if (FAILED(g_pImport->EnumInit(mdtProperty, cl, &hEnumProp))) goto FailedToEnum; + NumProps = g_pImport->EnumGetCount(&hEnumProp); + NumMembers += NumProps; + ret = TRUE; + + if(NumMembers) + { + pMemberList = new (nothrow) mdToken[NumMembers]; + if(pMemberList == NULL) ret = FALSE; + } + if ((NumMembers == 0)||(pMemberList == NULL)) goto CloseHandlesAndReturn; + + for (i = 0; g_pImport->EnumNext(&hEnumField, &pMemberList[i]); i++); + for (; g_pImport->EnumNext(&hEnumMethod, &pMemberList[i]); i++); + for (; g_pImport->EnumNext(&hEnumEvent, &pMemberList[i]); i++); + for (; g_pImport->EnumNext(&hEnumProp, &pMemberList[i]); i++); + _ASSERTE(i == NumMembers); + + for (i = 0; i < NumMembers; i++) + { + mdToken tk = pMemberList[i]; + if(g_pImport->IsValidToken(tk)) + { + switch (TypeFromToken(tk)) + { + case mdtFieldDef: + ret = DumpField(pMemberList[i], pszClassName, GUICookie,TRUE); + break; + + case mdtMethodDef: + ret = DumpMethod(pMemberList[i], pszClassName, dwEntryPointToken,GUICookie,TRUE); + break; + + case mdtEvent: + ret = DumpEvent(pMemberList[i], pszClassName, dwClassAttrs,GUICookie,TRUE); + break; + + case mdtProperty: + ret = DumpProp(pMemberList[i], pszClassName, dwClassAttrs,GUICookie,TRUE); + break; + + default: + { + char szStr[4096]; + sprintf_s(szStr,4096,RstrUTF(IDS_E_ODDMEMBER),pMemberList[i],pszClassName); + printLine(GUICookie,szStr); + } + ret = FALSE; + break; + } // end switch + } + else + { + char szStr[256]; + sprintf_s(szStr,256,ERRORMSG("INVALID MEMBER TOKEN: 0x%8.8X"),tk); + printLine(GUICookie,szStr); + ret= FALSE; + } + if(ret && (g_Mode == MODE_DUMP_CLASS_METHOD_SIG)) break; + } // end for + ret = TRUE; + +CloseHandlesAndReturn: + g_pImport->EnumClose(&hEnumMethod); + g_pImport->EnumClose(&hEnumField); + g_pImport->EnumClose(&hEnumEvent); + g_pImport->EnumClose(&hEnumProp); + if(pMemberList) delete[] pMemberList; + return ret; +} +BOOL GetClassLayout(mdTypeDef cl, ULONG* pulPackSize, ULONG* pulClassSize) +{ // Dump class layout + HENUMInternal hEnumField; + BOOL ret = FALSE; + + if(g_rFieldOffset) + VDELETE(g_rFieldOffset); + g_cFieldOffsets = 0; + g_cFieldsMax = 0; + + if(RidFromToken(cl)==0) return TRUE; + + if (SUCCEEDED(g_pImport->EnumInit(mdtFieldDef, cl, &hEnumField))) + { + g_cFieldsMax = g_pImport->EnumGetCount(&hEnumField); + g_pImport->EnumClose(&hEnumField); + } + + if(SUCCEEDED(g_pImport->GetClassPackSize(cl,pulPackSize))) ret = TRUE; + else *pulPackSize = 0xFFFFFFFF; + if(SUCCEEDED(g_pImport->GetClassTotalSize(cl,pulClassSize))) ret = TRUE; + else *pulClassSize = 0xFFFFFFFF; + + if(g_cFieldsMax) + { + MD_CLASS_LAYOUT Layout; + if(SUCCEEDED(g_pImport->GetClassLayoutInit(cl,&Layout))) + { + g_rFieldOffset = new COR_FIELD_OFFSET[g_cFieldsMax+1]; + if(g_rFieldOffset) + { + COR_FIELD_OFFSET* pFO = g_rFieldOffset; + for(g_cFieldOffsets=0; + SUCCEEDED(g_pImport->GetClassLayoutNext(&Layout,&(pFO->ridOfField),&(pFO->ulOffset))) + &&RidFromToken(pFO->ridOfField); + g_cFieldOffsets++, pFO++) ret = TRUE; + } + } + } + return ret; +} + +BOOL IsANestedInB(mdTypeDef A, mdTypeDef B) +{ + DWORD i; + for(i = 0; i < g_NumClasses; i++) + { + if(g_cl_list[i] == A) + { + A = g_cl_enclosing[i]; + if(A == B) return TRUE; + if(A == mdTypeDefNil) return FALSE; + return IsANestedInB(A,B); + } + } + return FALSE; +} +mdTypeDef TopEncloser(mdTypeDef A) +{ + DWORD i; + for(i = 0; i < g_NumClasses; i++) + { + if(g_cl_list[i] == A) + { + if(g_cl_enclosing[i] == mdTypeDefNil) return A; + return TopEncloser(g_cl_enclosing[i]); + } + } + return A; +} + +BOOL DumpClass(mdTypeDef cl, DWORD dwEntryPointToken, void* GUICookie, ULONG WhatToDump) +// WhatToDump: 0-title,flags,extends,implements; +// +1-pack,size and custom attrs; +// +2-nested classes +// +4-members +{ + char *pszClassName; // name associated with this CL + char *pszNamespace; + const char *pc1,*pc2; + DWORD dwClassAttrs; + mdTypeRef crExtends; + HRESULT hr; + mdInterfaceImpl ii; + DWORD NumInterfaces; + DWORD i; + HENUMInternal hEnumII; // enumerator for interface impl + //char *szString; + char* szptr; + + mdToken tkVarOwner = g_tkVarOwner; + ULONG WhatToDumpOrig = WhatToDump; + + if (FAILED(g_pImport->GetNameOfTypeDef( + cl, + &pc1, //&pszClassName, + &pc2))) //&pszNamespace + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), cl); + printError(GUICookie, sz); + g_tkVarOwner = tkVarOwner; + return FALSE; + } + MAKE_NAME_IF_NONE(pc1,cl); + + if (g_Mode == MODE_DUMP_CLASS || g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG) + { + if(cl != g_tkClassToDump) + { + if(IsANestedInB(g_tkClassToDump,cl)) + WhatToDump = 2; // nested classes only + else + return TRUE; + } + } + + if (FAILED(g_pImport->GetTypeDefProps( + cl, + &dwClassAttrs, + &crExtends))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), cl); + printError(GUICookie, sz); + g_tkVarOwner = tkVarOwner; + return FALSE; + } + + if(g_fLimitedVisibility) + { + if(g_fHidePub && (IsTdPublic(dwClassAttrs)||IsTdNestedPublic(dwClassAttrs))) return FALSE; + if(g_fHidePriv && (IsTdNotPublic(dwClassAttrs)||IsTdNestedPrivate(dwClassAttrs))) return FALSE; + if(g_fHideFam && IsTdNestedFamily(dwClassAttrs)) return FALSE; + if(g_fHideAsm && IsTdNestedAssembly(dwClassAttrs)) return FALSE; + if(g_fHideFOA && IsTdNestedFamORAssem(dwClassAttrs)) return FALSE; + if(g_fHideFAA && IsTdNestedFamANDAssem(dwClassAttrs)) return FALSE; + } + + g_tkVarOwner = cl; + + pszClassName = (char*)(pc1 ? pc1 : ""); + pszNamespace = (char*)(pc2 ? pc2 : ""); + +#if (0) + + if((!IsTdNested(dwClassAttrs))&&(!(g_Mode & MODE_GUI))) // don't dump namespaces in GUI mode! + { + // take care of namespace, if any + if(strcmp(pszNamespace,g_szNamespace)) + { + if(strlen(g_szNamespace)) + { + if(g_szAsmCodeIndent[0]) g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,UNSCOPE()); + sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// end of namespace %s"),ProperName(g_szNamespace)); + printLine(GUICookie,szString); + printLine(GUICookie,""); + } + strcpy_s(g_szNamespace,MAX_MEMBER_LENGTH,pszNamespace); + if(strlen(g_szNamespace)) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s", + g_szAsmCodeIndent,KEYWORD(".namespace"), ProperName(g_szNamespace)); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + } + } + } + +#endif + + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".class")); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%8.8X*/ "),cl); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)0)); + if (IsTdInterface(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"interface "); + if (IsTdPublic(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"public "); + if (IsTdNotPublic(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"private "); + if (IsTdAbstract(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"abstract "); + if (IsTdAutoLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"auto "); + if (IsTdSequentialLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"sequential "); + if (IsTdExplicitLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"explicit "); + if (IsTdAnsiClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"ansi "); + if (IsTdUnicodeClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"unicode "); + if (IsTdAutoClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"autochar "); + if (IsTdImport(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"import "); + if (IsTdWindowsRuntime(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"windowsruntime "); + if (IsTdSerializable(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"serializable "); + if (IsTdSealed(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"sealed "); + if (IsTdNestedPublic(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"nested public "); + if (IsTdNestedPrivate(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"nested private "); + if (IsTdNestedFamily(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"nested family "); + if (IsTdNestedAssembly(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"nested assembly "); + if (IsTdNestedFamANDAssem(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"nested famandassem "); + if (IsTdNestedFamORAssem(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"nested famorassem "); + if (IsTdBeforeFieldInit(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"beforefieldinit "); + if (IsTdSpecialName(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"specialname "); + if (IsTdRTSpecialName(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"rtspecialname "); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD((char*)-1)); + if(*pszNamespace != 0) + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s.",ProperName(pszNamespace)); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),WhatToDump > 2 ? ANCHORPT(ProperName(pszClassName),cl) : JUMPPT(ProperName(pszClassName),cl)); + + szptr = DumpGenericPars(szString, cl, GUICookie,TRUE); + if (szptr == NULL) + { + g_tkVarOwner = tkVarOwner; + return FALSE; + } + + printLine(GUICookie,szString); + if (!IsNilToken(crExtends)) + { + CQuickBytes out; + szptr = szString; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s %s ",g_szAsmCodeIndent,KEYWORD("extends")); + if(g_pImport->IsValidToken(crExtends)) + PrettyPrintToken(szString, crExtends, g_pImport,GUICookie,cl); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG("INVALID TOKEN: 0x%8.8X"),crExtends); + printLine(GUICookie,szString); + } + + hr = g_pImport->EnumInit( + mdtInterfaceImpl, + cl, + &hEnumII); + if (FAILED(hr)) + { + printError(GUICookie,RstrUTF(IDS_E_ENUMINIT)); + g_tkVarOwner = tkVarOwner; + return FALSE; + } + + NumInterfaces = g_pImport->EnumGetCount(&hEnumII); + + if (NumInterfaces > 0) + { + CQuickBytes out; + mdTypeRef crInterface; + for (i=0; g_pImport->EnumNext(&hEnumII, &ii); i++) + { + szptr = szString; + if(i) szptr+=sprintf_s(szptr,SZSTRING_SIZE, "%s ",g_szAsmCodeIndent); + else szptr+=sprintf_s(szptr,SZSTRING_SIZE, "%s %s ",g_szAsmCodeIndent,KEYWORD("implements")); + if (FAILED(g_pImport->GetTypeOfInterfaceImpl(ii, &crInterface))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), ii); + printError(GUICookie, sz); + g_tkVarOwner = tkVarOwner; + return FALSE; + } + if(g_pImport->IsValidToken(crInterface)) + PrettyPrintToken(szString, crInterface, g_pImport,GUICookie,cl); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG("INVALID TOKEN: 0x%8.8X"),crInterface); + if(i < NumInterfaces-1) strcat_s(szString, SZSTRING_SIZE,","); + printLine(GUICookie,szString); + out.Shrink(0); + } + // The assertion will fire if the enumerator is bad + _ASSERTE(NumInterfaces == i); + + g_pImport->EnumClose(&hEnumII); + } + if(WhatToDump == 0) // 0 = title only + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,SCOPE(),UNSCOPE()); + printLine(GUICookie,szString); + g_tkVarOwner = tkVarOwner; + return TRUE; + } + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + + ULONG ulPackSize=0xFFFFFFFF,ulClassSize=0xFFFFFFFF; + if(WhatToDump & 1) + { + if(GetClassLayout(cl,&ulPackSize,&ulClassSize)) + { // Dump class layout + if(ulPackSize != 0xFFFFFFFF) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s %d",g_szAsmCodeIndent,KEYWORD(".pack"),ulPackSize); + printLine(GUICookie,szString); + } + if(ulClassSize != 0xFFFFFFFF) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s %d",g_szAsmCodeIndent,KEYWORD(".size"),ulClassSize); + printLine(GUICookie,szString); + } + } + DumpCustomAttributes(cl,GUICookie); + // Dev11 #10745 + // Dump InterfaceImpl custom attributes here + if (NumInterfaces > 0 && g_fShowCA) + { + hr = g_pImport->EnumInit( + mdtInterfaceImpl, + cl, + &hEnumII); + if (FAILED(hr)) + { + printError(GUICookie,RstrUTF(IDS_E_ENUMINIT)); + g_tkVarOwner = tkVarOwner; + return FALSE; + } + + ASSERT_AND_CHECK(NumInterfaces == g_pImport->EnumGetCount(&hEnumII)); + CQuickBytes out; + mdTypeRef crInterface; + for (i = 0; g_pImport->EnumNext(&hEnumII, &ii); i++) + { + HENUMInternal hEnum; + mdCustomAttribute tkCA; + bool fFirst = true; + + if (FAILED(g_pImport->EnumInit(mdtCustomAttribute, ii,&hEnum))) + { + return FALSE; + } + while(g_pImport->EnumNext(&hEnum,&tkCA) && RidFromToken(tkCA)) + { + if (fFirst) + { + // Print .interfaceImpl type {type} before the custom attribute list + szptr = szString; + szptr += sprintf_s(szptr, SZSTRING_SIZE, "%s.%s ", g_szAsmCodeIndent, KEYWORD("interfaceimpl type")); + if (FAILED(g_pImport->GetTypeOfInterfaceImpl(ii, &crInterface))) + { + char sz[2048]; + sprintf_s(sz, 2048, RstrUTF(IDS_E_INVALIDRECORD), ii); + printError(GUICookie, sz); + g_tkVarOwner = tkVarOwner; + return FALSE; + } + if(g_pImport->IsValidToken(crInterface)) + PrettyPrintToken(szString, crInterface, g_pImport,GUICookie,cl); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG("INVALID TOKEN: 0x%8.8X"),crInterface); + printLine(GUICookie,szString); + out.Shrink(0); + + szptr = szString; + fFirst = false; + } + DumpCustomAttribute(tkCA,GUICookie,false); + } + g_pImport->EnumClose( &hEnum); + } + // The assertion will fire if the enumerator is bad + _ASSERTE(NumInterfaces == i); + + g_pImport->EnumClose(&hEnumII); + } + DumpGenericParsCA(cl,GUICookie); + DumpPermissions(cl,GUICookie); + } + + // Dump method impls declared in this class whose implementing methods belong somewhere else: + if(WhatToDump & 1) // 1 - dump headers + { + for(i = 0; i < g_NumMI; i++) + { + if(((*g_pmi_list)[i].tkClass == cl)&&((*g_pmi_list)[i].tkBodyParent != cl)) + { + BOOL bOverridingTypeSpec; + PrettyPrintOverrideDecl(i,szString,GUICookie,cl,&bOverridingTypeSpec); + strcat_s(szString, SZSTRING_SIZE,KEYWORD(" with ")); + + if (bOverridingTypeSpec) + { + // If PrettyPrintOverrideDecl printed the 'method' keyword, we need it here as well + // to satisfy the following grammar rule (simplified): + // _OVERRIDE METHOD_ ... DCOLON methodName ... WITH_ METHOD_ ... DCOLON methodName ... + strcat_s(szString, SZSTRING_SIZE,KEYWORD("method ")); + } + + PrettyPrintToken(szString, (*g_pmi_list)[i].tkBody, g_pImport,GUICookie,0); + printLine(GUICookie,szString); + } + } + } + if(WhatToDump & 2) // nested classes + { + BOOL fRegetClassLayout=FALSE; + DWORD dwMode = g_Mode; + + if(g_Mode == MODE_DUMP_CLASS) + g_Mode = MODE_DUMP_ALL; + + for(i = 0; i < g_NumClasses; i++) + { + if(g_cl_enclosing[i] == cl) + { + DumpClass(g_cl_list[i],dwEntryPointToken,GUICookie,WhatToDumpOrig); + if(g_fAbortDisassembly) + { + g_Mode = dwMode; + return FALSE; + } + fRegetClassLayout = TRUE; + } + } + if(fRegetClassLayout) GetClassLayout(cl,&ulPackSize,&ulClassSize); + g_Mode = dwMode; + } + + if(WhatToDump & 4) + { + DumpMembers(cl, pszNamespace, pszClassName, dwClassAttrs, dwEntryPointToken,GUICookie); + if(!ProgressStep()) g_fAbortDisassembly = TRUE; + } + + if(g_szAsmCodeIndent[0]) g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + szptr = szString; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s %s// end of class ",g_szAsmCodeIndent,UNSCOPE(),COMMENT((char*)0)); + if(*pszNamespace != 0) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s.",ProperName(pszNamespace)); + sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%s", ProperName(pszClassName),COMMENT((char*)-1)); + printLine(GUICookie,szString); + if(!(g_Mode & MODE_GUI)) + { + printLine(GUICookie,""); + } + g_tkVarOwner = tkVarOwner; + return TRUE; +} + + + +void DumpGlobalMethods(DWORD dwEntryPointToken) +{ + HENUMInternal hEnumMethod; + mdToken FuncToken; + DWORD i; + CQuickBytes qbMemberSig; + + if (FAILED(g_pImport->EnumGlobalFunctionsInit(&hEnumMethod))) + return; + + for (i = 0; g_pImport->EnumNext(&hEnumMethod, &FuncToken); i++) + { + if ((i == 0)&&(!(g_Mode & MODE_GUI))) + { + printLine(g_pFile,""); + printLine(g_pFile,COMMENT("// ================== GLOBAL METHODS =========================")); + printLine(g_pFile,""); + } + if(DumpMethod(FuncToken, NULL, dwEntryPointToken, g_pFile, TRUE)&& + (g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG)) break; + + if(!ProgressStep()) + { + g_fAbortDisassembly = TRUE; + break; + } + } + g_pImport->EnumClose(&hEnumMethod); + if(i) + { + printLine(g_pFile,""); + printLine(g_pFile,COMMENT("// =============================================================")); + printLine(g_pFile,""); + } +} + +void DumpGlobalFields() +{ + HENUMInternal hEnum; + mdToken FieldToken; + DWORD i; + CQuickBytes qbMemberSig; + + if (FAILED(g_pImport->EnumGlobalFieldsInit(&hEnum))) + return; + + for (i = 0; g_pImport->EnumNext(&hEnum, &FieldToken); i++) + { + if ((i == 0)&&(!(g_Mode & MODE_GUI))) + { + printLine(g_pFile,""); + printLine(g_pFile,COMMENT("// ================== GLOBAL FIELDS ==========================")); + printLine(g_pFile,""); + } + if(DumpField(FieldToken, NULL, g_pFile, TRUE)&& + (g_Mode == MODE_DUMP_CLASS_METHOD || g_Mode == MODE_DUMP_CLASS_METHOD_SIG)) break; + } + g_pImport->EnumClose(&hEnum); + if(i) + { + printLine(g_pFile,""); + printLine(g_pFile,COMMENT("// =============================================================")); + printLine(g_pFile,""); + } +} + +void DumpVTables(IMAGE_COR20_HEADER *CORHeader, void* GUICookie) +{ + IMAGE_COR_VTABLEFIXUP *pFixup,*pDummy; + DWORD iCount; + DWORD i; + USHORT iSlot; + char* szStr = &szString[0]; + + if (VAL32(CORHeader->VTableFixups.VirtualAddress) == 0) return; + + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + + sprintf_s(szString,SZSTRING_SIZE,"// VTableFixup Directory:"); + printLine(GUICookie,szStr); + + // Pull back a pointer to the guy. + iCount = VAL32(CORHeader->VTableFixups.Size) / sizeof(IMAGE_COR_VTABLEFIXUP); + if ((g_pPELoader->getVAforRVA(VAL32(CORHeader->VTableFixups.VirtualAddress), (void **) &pFixup) == FALSE) + ||(g_pPELoader->getVAforRVA(VAL32(CORHeader->VTableFixups.VirtualAddress)+VAL32(CORHeader->VTableFixups.Size)-1, (void **) &pDummy) == FALSE)) + { + printLine(GUICookie,RstrUTF(IDS_E_VTFUTABLE)); + goto exit; + } + + // Walk every v-table fixup entry and dump the slots. + for (i=0; i<iCount; i++) + { + sprintf_s(szString,SZSTRING_SIZE,"// IMAGE_COR_VTABLEFIXUP[%d]:", i); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// RVA: 0x%08x", VAL32(pFixup->RVA)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Count: 0x%04x", VAL16(pFixup->Count)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Type: 0x%04x", VAL16(pFixup->Type)); + printLine(GUICookie,szStr); + + BYTE *pSlot; + if (g_pPELoader->getVAforRVA(VAL32(pFixup->RVA), (void **) &pSlot) == FALSE) + { + printLine(GUICookie,RstrUTF(IDS_E_BOGUSRVA)); + goto NextEntry; + } + + for (iSlot=0; iSlot<pFixup->Count; iSlot++) + { + mdMethodDef tkMethod = VAL32(*(DWORD *) pSlot); + if (pFixup->Type & VAL16(COR_VTABLE_32BIT)) + { + sprintf_s(szString,SZSTRING_SIZE,"// [0x%04x] (0x%08x)", iSlot, tkMethod); + pSlot += sizeof(DWORD); + } + else + { + sprintf_s(szString,SZSTRING_SIZE,"// [0x%04x] (0x%16x)", iSlot, VAL64(*(unsigned __int64 *) pSlot)); + pSlot += sizeof(unsigned __int64); + } + printLine(GUICookie,szStr); + + ValidateToken(tkMethod, mdtMethodDef); + } + + // Pointer to next fixup entry. +NextEntry: + ++pFixup; + } + +exit: + printLine(GUICookie,""); +} + + +void DumpEATTable(IMAGE_COR20_HEADER *CORHeader, void* GUICookie) +{ + BYTE *pFixup,*pDummy; + DWORD iCount; + DWORD BufferRVA; + DWORD i; + char* szStr = &szString[0]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + + sprintf_s(szString,SZSTRING_SIZE,"// Export Address Table Jumps:"); + printLine(GUICookie,szStr); + + if (VAL32(CORHeader->ExportAddressTableJumps.VirtualAddress) == 0) + { + printLine(GUICookie,RstrUTF(IDS_E_NODATA)); + return; + } + + // Pull back a pointer to the guy. + iCount = VAL32(CORHeader->ExportAddressTableJumps.Size) / IMAGE_COR_EATJ_THUNK_SIZE; + if ((g_pPELoader->getVAforRVA(VAL32(CORHeader->ExportAddressTableJumps.VirtualAddress), (void **) &pFixup) == FALSE) + ||(g_pPELoader->getVAforRVA(VAL32(CORHeader->ExportAddressTableJumps.VirtualAddress)+VAL32(CORHeader->ExportAddressTableJumps.Size)-1, (void **) &pDummy) == FALSE)) + { + printLine(GUICookie,RstrUTF(IDS_E_EATJTABLE)); + goto exit; + } + + // Quick sanity check on the linker. + if (VAL32(CORHeader->ExportAddressTableJumps.Size) % IMAGE_COR_EATJ_THUNK_SIZE) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_EATJSIZE), + VAL32(CORHeader->ExportAddressTableJumps.Size), IMAGE_COR_EATJ_THUNK_SIZE); + printLine(GUICookie,szStr); + } + + // Walk every v-table fixup entry and dump the slots. + BufferRVA = VAL32(CORHeader->ExportAddressTableJumps.VirtualAddress); + for (i=0; i<iCount; i++) + { + ULONG ReservedFlag = VAL32(*(ULONG *) (pFixup + sizeof(ULONG))); + sprintf_s(szString,SZSTRING_SIZE,"// Fixup Jump Entry [%d], at RVA 0x%08x:", i, BufferRVA); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// RVA of slot: 0x%08x", VAL32(*(ULONG *) pFixup)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Reserved flag: 0x%08x", ReservedFlag); + printLine(GUICookie,szStr); + if (ReservedFlag != 0) + { + printLine(GUICookie,RstrUTF(IDS_E_RESFLAGS)); + } + + pFixup += IMAGE_COR_EATJ_THUNK_SIZE; + BufferRVA += IMAGE_COR_EATJ_THUNK_SIZE; + } + +exit: + printLine(GUICookie,""); +} + + +void DumpCodeManager(IMAGE_COR20_HEADER *CORHeader, void* GUICookie) +{ + char* szStr = &szString[0]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + sprintf_s(szString,SZSTRING_SIZE,"// Code Manager Table:"); + printLine(GUICookie,szStr); + if (!VAL32(CORHeader->CodeManagerTable.Size)) + { + sprintf_s(szString,SZSTRING_SIZE,"// default"); + printLine(GUICookie,szStr); + return; + } + + const GUID *pcm; + if (g_pPELoader->getVAforRVA(VAL32(CORHeader->CodeManagerTable.VirtualAddress), (void **) &pcm) == FALSE) + { + printLine(GUICookie,RstrUTF(IDS_E_CODEMGRTBL)); + return; + } + + sprintf_s(szString,SZSTRING_SIZE,"// [index] ID"); + printLine(GUICookie,szStr); + ULONG iCount = VAL32(CORHeader->CodeManagerTable.Size) / sizeof(GUID); + for (ULONG i=0; i<iCount; i++) + { + WCHAR rcguid[128]; + GUID Guid = *pcm; + SwapGuid(&Guid); + StringFromGUID2(Guid, rcguid, NumItems(rcguid)); + sprintf_s(szString,SZSTRING_SIZE,"// [0x%08x] %S", i, rcguid); + printLine(GUICookie,szStr); + pcm++; + } + printLine(GUICookie,""); +} + +void DumpSectionHeaders(IMAGE_SECTION_HEADER* pSH, USHORT nSH, void* GUICookie) +{ + char* szStr = &szString[0]; + char name[16]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + printLine(GUICookie,""); + strcpy_s(szString,SZSTRING_SIZE,"// Image sections:"); + printLine(GUICookie,szStr); + for(USHORT iSH=0; iSH < nSH; iSH++,pSH++) + { + strncpy_s(name,16,(const char*)(pSH->Name),8); + name[8]=0; + sprintf_s(szString,SZSTRING_SIZE,"// %s",name); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Virtual Size", pSH->Misc.VirtualSize); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Virtual Address", pSH->VirtualAddress); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Size of Raw Data", pSH->SizeOfRawData); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Pointer to Raw Data", pSH->PointerToRawData); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Pointer to Relocations", pSH->PointerToRelocations); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Pointer to Linenumbers", pSH->PointerToLinenumbers); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%04x Number of Relocations", pSH->NumberOfRelocations); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%04x Number of Linenumbers", pSH->NumberOfLinenumbers); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Characteristics", pSH->Characteristics); + printLine(GUICookie,szStr); + if((pSH->Characteristics & IMAGE_SCN_SCALE_INDEX)) + { + strcpy_s(szString,SZSTRING_SIZE,"// SCALE_INDEX"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_CNT_CODE)) + { + strcpy_s(szString,SZSTRING_SIZE,"// CNT_CODE"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)) + { + strcpy_s(szString,SZSTRING_SIZE,"// CNT_INITIALIZED_DATA"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) + { + strcpy_s(szString,SZSTRING_SIZE,"// CNT_UNINITIALIZED_DATA"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_NO_DEFER_SPEC_EXC)) + { + strcpy_s(szString,SZSTRING_SIZE,"// NO_DEFER_SPEC_EXC"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_LNK_NRELOC_OVFL)) + { + strcpy_s(szString,SZSTRING_SIZE,"// LNK_NRELOC_OVFL"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)) + { + strcpy_s(szString,SZSTRING_SIZE,"// MEM_DISCARDABLE"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_MEM_NOT_CACHED)) + { + strcpy_s(szString,SZSTRING_SIZE,"// MEM_NOT_CACHED"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_MEM_NOT_PAGED)) + { + strcpy_s(szString,SZSTRING_SIZE,"// MEM_NOT_PAGED"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_MEM_SHARED)) + { + strcpy_s(szString,SZSTRING_SIZE,"// MEM_SHARED"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_MEM_EXECUTE)) + { + strcpy_s(szString,SZSTRING_SIZE,"// MEM_EXECUTE"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_MEM_READ)) + { + strcpy_s(szString,SZSTRING_SIZE,"// MEM_READ"); + printLine(GUICookie,szStr); + } + if((pSH->Characteristics & IMAGE_SCN_MEM_WRITE)) + { + strcpy_s(szString,SZSTRING_SIZE,"// MEM_WRITE"); + printLine(GUICookie,szStr); + } + printLine(GUICookie,""); + } +} + +void DumpBaseReloc(const char *szName, IMAGE_DATA_DIRECTORY *pDir, void* GUICookie) +{ + char* szStr = &szString[0]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + sprintf_s(szString,SZSTRING_SIZE,"// %s", szName); + printLine(GUICookie,szStr); + if (!VAL32(pDir->Size)) + { + printLine(GUICookie,RstrUTF(IDS_E_NODATA)); + return; + } + char *pBegin, *pEnd; + DWORD *pdw, i, Nentries; + WORD *pw; + if (g_pPELoader->getVAforRVA(VAL32(pDir->VirtualAddress), (void **) &pBegin) == FALSE) + { + printLine(GUICookie,RstrUTF(IDS_E_IMPORTDATA)); + return; + } + pEnd = pBegin + VAL32(pDir->Size); + for(pdw = (DWORD*)pBegin; pdw < (DWORD*)pEnd; ) + { + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Page RVA", *pdw); + printLine(GUICookie,szStr); + pdw++; + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Block Size", *pdw); + printLine(GUICookie,szStr); + Nentries = (*pdw - 2*sizeof(DWORD)) / sizeof(WORD); + pdw++; + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Number of Entries", Nentries); + printLine(GUICookie,szStr); + + for(i = 1, pw = (WORD*)pdw; i <= Nentries; i++, pw++) + { + sprintf_s(szString,SZSTRING_SIZE,"// Entry %d: Type 0x%x Offset 0x%08x", i, ((*pw)>>12), ((*pw)&0x0FFF)); + printLine(GUICookie,szStr); + } + if((Nentries & 1)) pw++; // to make pdw DWORD-aligned + pdw = (DWORD*)pw; + printLine(GUICookie,""); + } +} +void DumpIAT(const char *szName, IMAGE_DATA_DIRECTORY *pDir, void* GUICookie) +{ + char* szStr = &szString[0]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + sprintf_s(szString,SZSTRING_SIZE,"// %s", szName); + printLine(GUICookie,szStr); + if (!VAL32(pDir->Size)) + { + printLine(GUICookie,RstrUTF(IDS_E_NODATA)); + return; + } + + const char *szDLLName; + const IMAGE_IMPORT_DESCRIPTOR *pImportDesc; + + if (g_pPELoader->getVAforRVA(VAL32(pDir->VirtualAddress), (void **) &pImportDesc) == FALSE) + { + printLine(GUICookie,RstrUTF(IDS_E_IMPORTDATA)); + return; + } + + const DWORD *pImportTableID; + while (VAL32(pImportDesc->FirstThunk)) + { + if (g_pPELoader->getVAforRVA(VAL32(pImportDesc->Name), (void **) &szDLLName) == FALSE || + g_pPELoader->getVAforRVA(VAL32(pImportDesc->FirstThunk), (void **) &pImportTableID) == FALSE) + { + printLine(GUICookie,RstrUTF(IDS_E_IMPORTDATA)); + return; + } + + sprintf_s(szString,SZSTRING_SIZE,"// DLL : %s", szDLLName); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Import Address Table", VAL32(pImportDesc->FirstThunk)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Import Name Table", VAL32(pImportDesc->Name)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// %-8d Time Date Stamp", VAL32(pImportDesc->TimeDateStamp)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// %-8d Index of First Forwarder Reference", VAL32(pImportDesc->ForwarderChain)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"//"); + printLine(GUICookie,szStr); + + for ( ; VAL32(*pImportTableID); pImportTableID++) + { + if (VAL32(*pImportTableID) & 0x80000000) + sprintf_s(szString,SZSTRING_SIZE,"// by Ordinal %d", VAL32(*pImportTableID) & 0x7fffffff); + else + { + const IMAGE_IMPORT_BY_NAME *pName; + if(g_pPELoader->getVAforRVA(VAL32(*pImportTableID) & 0x7fffffff, (void **) &pName)) + sprintf_s(szString,SZSTRING_SIZE,"// 0x%04x %s", VAL16(pName->Hint), pName->Name); + else + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x bad RVA of IMAGE_IMPORT_BY_NAME", VAL32(*pImportTableID)); + } + printLine(GUICookie,szStr); + } + printLine(GUICookie,""); + + // Next import descriptor. + pImportDesc++; + } +} + +struct MDStreamHeader +{ + DWORD Reserved; + BYTE Major; + BYTE Minor; + BYTE Heaps; + BYTE Rid; + ULONGLONG MaskValid; + ULONGLONG Sorted; +}; + +void DumpMetadataHeader(const char *szName, IMAGE_DATA_DIRECTORY *pDir, void* GUICookie) +{ + char* szStr = &szString[0]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + printLine(GUICookie,""); + sprintf_s(szString,SZSTRING_SIZE,"// %s", szName); + printLine(GUICookie,szStr); + if (!VAL32(pDir->Size)) + { + printLine(GUICookie,RstrUTF(IDS_E_NODATA)); + return; + } + + const STORAGESIGNATURE *pSSig; + char verstr[1024]; + + if (g_pPELoader->getVAforRVA(VAL32(pDir->VirtualAddress), (void **) &pSSig) == FALSE) + { + printLine(GUICookie,RstrUTF(IDS_E_IMPORTDATA)); + return; + } + strcpy_s(szString,SZSTRING_SIZE,"// Storage Signature:"); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Signature", VAL32(pSSig->lSignature)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%04x Major Version", VAL16(pSSig->iMajorVer)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%04x Minor Version", VAL16(pSSig->iMinorVer)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Extra Data Offset", VAL32(pSSig->iExtraData)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Version String Length", VAL32(pSSig->iVersionString)); + printLine(GUICookie,szStr); + memset(verstr,0,1024); + strncpy_s(verstr,1024,(const char*)(pSSig->pVersion),VAL32(pSSig->iVersionString)); + sprintf_s(szString,SZSTRING_SIZE,"// '%s' Version String", verstr); + printLine(GUICookie,szStr); + + size_t pb = (size_t)pSSig; + pb += (3*sizeof(DWORD)+2*sizeof(WORD)+VAL32(pSSig->iVersionString)+3)&~3; + PSTORAGEHEADER pSHdr = (PSTORAGEHEADER)pb; + strcpy_s(szString,SZSTRING_SIZE,"// Storage Header:"); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%02x Flags", pSHdr->fFlags); + printLine(GUICookie,szStr); + short nStr = VAL16(pSHdr->iStreams); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%04x Number of Streams", nStr); + if(nStr > 5) + { + strcat_s(szString, SZSTRING_SIZE, " -- BOGUS!"); + nStr = 5; + } + printLine(GUICookie,szStr); + + PSTORAGESTREAM pStr = (PSTORAGESTREAM)(pSHdr+1); + BYTE* pbMDstream = NULL; + size_t cbMDstream = 0; + for(short iStr = 1; iStr <= nStr; iStr++) + { + sprintf_s(szString,SZSTRING_SIZE,"// Stream %d:",iStr); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Offset", VAL32(pStr->iOffset)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Size", VAL32(pStr->iSize)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// '%s' Name", pStr->rcName); + printLine(GUICookie,szStr); + if((strcmp(pStr->rcName,"#-")==0)||(strcmp(pStr->rcName,"#~")==0)) + { + pbMDstream = (BYTE*)pSSig + VAL32(pStr->iOffset); + cbMDstream = VAL32(pStr->iSize); + } + + pb = (size_t)pStr; + pb += (2*sizeof(DWORD)+strlen(pStr->rcName)+1+3)&~3; + pStr = (PSTORAGESTREAM)pb; + } + if((pbMDstream)&&(cbMDstream >= sizeof(MDStreamHeader))) + { + printLine(GUICookie,""); + strcpy_s(szString,SZSTRING_SIZE,"// Metadata Stream Header:"); + printLine(GUICookie,szStr); + + MDStreamHeader* pMDSH = (MDStreamHeader*)pbMDstream; + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x Reserved", VAL32(pMDSH->Reserved)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%02x Major", pMDSH->Major); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%02x Minor", pMDSH->Minor); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%02x Heaps", pMDSH->Heaps); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%02x Rid", pMDSH->Rid); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%016I64x MaskValid", (ULONGLONG)GET_UNALIGNED_VAL64(&(pMDSH->MaskValid))); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// 0x%016I64x Sorted", (ULONGLONG)GET_UNALIGNED_VAL64(&(pMDSH->Sorted))); + printLine(GUICookie,szStr); + } +} +void DumpEntryPoint(DWORD dwAddrOfEntryPoint,DWORD dwEntryPointSize,void* GUICookie) +{ + BYTE* pB; + char* szStr = &szString[0]; + char* szptr = szStr+2; + DWORD i; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + printLine(GUICookie,""); + strcpy_s(szString,SZSTRING_SIZE,"// Entry point code:"); + printLine(GUICookie,szStr); + if (g_pPELoader->getVAforRVA(dwAddrOfEntryPoint, (void **) &pB) == FALSE) + { + printLine(GUICookie,"Bad RVA of entry point"); + return; + } + if(dwEntryPointSize == 48) pB -= 32; + // on IA64, AddressOfEntryPoint points at PLabelDescriptor, not at the stub itself + for(i=0; i<dwEntryPointSize; i++) + { + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%2.2X ",pB[i]); + } + printLine(GUICookie,szStr); +} + +#define DUMP_DIRECTORY(szName, Directory) \ + sprintf_s(szString,SZSTRING_SIZE,"// 0x%08x [0x%08x] address [size] of " szName, \ + VAL32(Directory.VirtualAddress), VAL32(Directory.Size)); \ + printLine(GUICookie,szStr) + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +void DumpHeader(IMAGE_COR20_HEADER *CORHeader, void* GUICookie) +{ + char* szStr = &szString[0]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + DWORD dwAddrOfEntryPoint=0, dwEntryPointSize=0; + + PIMAGE_DOS_HEADER pDOSHeader = g_pPELoader->dosHeader(); + + strcpy_s(szString,SZSTRING_SIZE,"// ----- DOS Header:"); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Magic: 0x%04x", VAL16(pDOSHeader->e_magic)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Bytes on last page: 0x%04x", VAL16(pDOSHeader->e_cblp)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Pages in file: 0x%04x", VAL16(pDOSHeader->e_cp)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Relocations: 0x%04x", VAL16(pDOSHeader->e_crlc)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of header (paragraphs):0x%04x", VAL16(pDOSHeader->e_cparhdr)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Min extra paragraphs: 0x%04x", VAL16(pDOSHeader->e_minalloc)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Max extra paragraphs: 0x%04x", VAL16(pDOSHeader->e_maxalloc)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Initial (relative) SS: 0x%04x", VAL16(pDOSHeader->e_ss)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Initial SP: 0x%04x", VAL16(pDOSHeader->e_sp)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Checksum: 0x%04x", VAL16(pDOSHeader->e_csum)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Initial IP: 0x%04x", VAL16(pDOSHeader->e_ip)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Initial (relative) CS: 0x%04x", VAL16(pDOSHeader->e_ip)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// File addr. of reloc table: 0x%04x", VAL16(pDOSHeader->e_lfarlc)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Overlay number: 0x%04x", VAL16(pDOSHeader->e_ovno)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// OEM identifier: 0x%04x", VAL16(pDOSHeader->e_oemid)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// OEM info: 0x%04x", VAL16(pDOSHeader->e_oeminfo)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// File addr. of COFF header: 0x%04x", VAL16(pDOSHeader->e_lfanew)); + printLine(GUICookie,szStr); + + strcpy_s(szString,SZSTRING_SIZE,"// ----- COFF/PE Headers:"); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Signature: 0x%08x", VAL32(g_pPELoader->Signature())); + printLine(GUICookie,szStr); + + strcpy_s(szString,SZSTRING_SIZE,"// ----- COFF Header:"); + printLine(GUICookie,szStr); + + PIMAGE_FILE_HEADER pCOFF = g_pPELoader->coffHeader(); + sprintf_s(szString,SZSTRING_SIZE,"// Machine: 0x%04x", VAL16(pCOFF->Machine)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Number of sections: 0x%04x", VAL16(pCOFF->NumberOfSections)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Time-date stamp: 0x%08x", VAL32(pCOFF->TimeDateStamp)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Ptr to symbol table: 0x%08x", VAL32(pCOFF->PointerToSymbolTable)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Number of symbols: 0x%08x", VAL32(pCOFF->NumberOfSymbols)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of optional header: 0x%04x", VAL16(pCOFF->SizeOfOptionalHeader)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Characteristics: 0x%04x", VAL16(pCOFF->Characteristics)); + printLine(GUICookie,szStr); + + + if (g_pPELoader->IsPE32()) + { + IMAGE_NT_HEADERS32 *pNTHeader = g_pPELoader->ntHeaders32(); + IMAGE_OPTIONAL_HEADER32 *pOptHeader = &pNTHeader->OptionalHeader; + + strcpy_s(szString,SZSTRING_SIZE,"// ----- PE Optional Header (32 bit):"); + printLine(GUICookie,szStr); + + sprintf_s(szString,SZSTRING_SIZE,"// Magic: 0x%04x", VAL16(pOptHeader->Magic)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major linker version: 0x%02x", VAL16(pOptHeader->MajorLinkerVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor linker version: 0x%02x", VAL16(pOptHeader->MinorLinkerVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of code: 0x%08x", VAL32(pOptHeader->SizeOfCode)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of init.data: 0x%08x", VAL32(pOptHeader->SizeOfInitializedData)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of uninit.data: 0x%08x", VAL32(pOptHeader->SizeOfUninitializedData)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Addr. of entry point: 0x%08x", VAL32(pOptHeader->AddressOfEntryPoint)); + printLine(GUICookie,szStr); + dwAddrOfEntryPoint = VAL32(pOptHeader->AddressOfEntryPoint); + dwEntryPointSize = 6; + sprintf_s(szString,SZSTRING_SIZE,"// Base of code: 0x%08x", VAL32(pOptHeader->BaseOfCode)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Base of data: 0x%08x", VAL32(pOptHeader->BaseOfData)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Image base: 0x%08x", VAL32(pOptHeader->ImageBase)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Section alignment: 0x%08x", VAL32(pOptHeader->SectionAlignment)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// File alignment: 0x%08x", VAL32(pOptHeader->FileAlignment)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major OS version: 0x%04x", VAL16(pOptHeader->MajorOperatingSystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor OS version: 0x%04x", VAL16(pOptHeader->MinorOperatingSystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major image version: 0x%04x", VAL16(pOptHeader->MajorImageVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor image version: 0x%04x", VAL16(pOptHeader->MinorImageVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major subsystem version: 0x%04x", VAL16(pOptHeader->MajorSubsystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor subsystem version: 0x%04x", VAL16(pOptHeader->MinorSubsystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of image: 0x%08x", VAL32(pOptHeader->SizeOfImage)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of headers: 0x%08x", VAL32(pOptHeader->SizeOfHeaders)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Checksum: 0x%08x", VAL32(pOptHeader->CheckSum)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Subsystem: 0x%04x", VAL16(pOptHeader->Subsystem)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// DLL characteristics: 0x%04x", VAL16(pOptHeader->DllCharacteristics)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of stack reserve: 0x%08x", VAL32(pOptHeader->SizeOfStackReserve)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of stack commit: 0x%08x", VAL32(pOptHeader->SizeOfStackCommit)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of heap reserve: 0x%08x", VAL32(pOptHeader->SizeOfHeapReserve)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of heap commit: 0x%08x", VAL32(pOptHeader->SizeOfHeapCommit)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Loader flags: 0x%08x", VAL32(pOptHeader->LoaderFlags)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Directories: 0x%08x", VAL32(pOptHeader->NumberOfRvaAndSizes)); + printLine(GUICookie,szStr); + DUMP_DIRECTORY("Export Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]); + DUMP_DIRECTORY("Import Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]); + DUMP_DIRECTORY("Resource Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]); + DUMP_DIRECTORY("Exception Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]); + DUMP_DIRECTORY("Security Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]); + DUMP_DIRECTORY("Base Relocation Table: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]); + DUMP_DIRECTORY("Debug Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]); + DUMP_DIRECTORY("Architecture Specific: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE]); + DUMP_DIRECTORY("Global Pointer: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR]); + DUMP_DIRECTORY("TLS Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS]); + DUMP_DIRECTORY("Load Config Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]); + DUMP_DIRECTORY("Bound Import Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]); + DUMP_DIRECTORY("Import Address Table: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]); + DUMP_DIRECTORY("Delay Load IAT: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]); + DUMP_DIRECTORY("CLR Header: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]); + printLine(GUICookie,""); + + DumpSectionHeaders((IMAGE_SECTION_HEADER*)(pOptHeader+1),pNTHeader->FileHeader.NumberOfSections,GUICookie); + DumpBaseReloc("Base Relocation Table",&pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC],GUICookie); + DumpIAT("Import Address Table", &pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT],GUICookie); + DumpIAT("Delay Load Import Address Table", &pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT],GUICookie); + } + else + { + IMAGE_NT_HEADERS64 *pNTHeader = g_pPELoader->ntHeaders64(); + IMAGE_OPTIONAL_HEADER64 *pOptHeader = &pNTHeader->OptionalHeader; + + strcpy_s(szString,SZSTRING_SIZE,"// ----- PE Optional Header (64 bit):"); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Magic: 0x%04x", VAL16(pOptHeader->Magic)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major linker version: 0x%02x", VAL16(pOptHeader->MajorLinkerVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor linker version: 0x%02x", VAL16(pOptHeader->MinorLinkerVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of code: 0x%08x", VAL32(pOptHeader->SizeOfCode)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of init.data: 0x%08x", VAL32(pOptHeader->SizeOfInitializedData)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of uninit.data: 0x%08x", VAL32(pOptHeader->SizeOfUninitializedData)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Addr. of entry point: 0x%08x", VAL32(pOptHeader->AddressOfEntryPoint)); + printLine(GUICookie,szStr); + dwAddrOfEntryPoint = VAL32(pOptHeader->AddressOfEntryPoint); + dwEntryPointSize = (VAL16(pCOFF->Machine)==IMAGE_FILE_MACHINE_IA64) ? 48 : 12; + sprintf_s(szString,SZSTRING_SIZE,"// Base of code: 0x%08x", VAL32(pOptHeader->BaseOfCode)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Image base: 0x%016I64x", VAL64(pOptHeader->ImageBase)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Section alignment: 0x%08x", VAL32(pOptHeader->SectionAlignment)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// File alignment: 0x%08x", VAL32(pOptHeader->FileAlignment)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major OS version: 0x%04x", VAL16(pOptHeader->MajorOperatingSystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor OS version: 0x%04x", VAL16(pOptHeader->MinorOperatingSystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major image version: 0x%04x", VAL16(pOptHeader->MajorImageVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor image version: 0x%04x", VAL16(pOptHeader->MinorImageVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major subsystem version: 0x%04x", VAL16(pOptHeader->MajorSubsystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor subsystem version: 0x%04x", VAL16(pOptHeader->MinorSubsystemVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of image: 0x%08x", VAL32(pOptHeader->SizeOfImage)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of headers: 0x%08x", VAL32(pOptHeader->SizeOfHeaders)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Checksum: 0x%08x", VAL32(pOptHeader->CheckSum)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Subsystem: 0x%04x", VAL16(pOptHeader->Subsystem)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// DLL characteristics: 0x%04x", VAL16(pOptHeader->DllCharacteristics)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of stack reserve: 0x%016I64x", VAL64(pOptHeader->SizeOfStackReserve)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of stack commit: 0x%016I64x", VAL64(pOptHeader->SizeOfStackCommit)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of heap reserve: 0x%016I64x", VAL64(pOptHeader->SizeOfHeapReserve)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Size of heap commit: 0x%016I64x", VAL64(pOptHeader->SizeOfHeapCommit)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Loader flags: 0x%08x", VAL32(pOptHeader->LoaderFlags)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Directories: 0x%08x", VAL32(pOptHeader->NumberOfRvaAndSizes)); + printLine(GUICookie,szStr); + + DUMP_DIRECTORY("Export Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]); + DUMP_DIRECTORY("Import Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]); + DUMP_DIRECTORY("Resource Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]); + DUMP_DIRECTORY("Exception Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]); + DUMP_DIRECTORY("Security Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]); + DUMP_DIRECTORY("Base Relocation Table: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]); + DUMP_DIRECTORY("Debug Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]); + DUMP_DIRECTORY("Architecture Specific: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE]); + DUMP_DIRECTORY("Global Pointer: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR]); + DUMP_DIRECTORY("TLS Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS]); + DUMP_DIRECTORY("Load Config Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]); + DUMP_DIRECTORY("Bound Import Directory: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]); + DUMP_DIRECTORY("Import Address Table: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]); + DUMP_DIRECTORY("Delay Load IAT: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]); + DUMP_DIRECTORY("CLR Header: ", pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]); + printLine(GUICookie,""); + + DumpSectionHeaders((IMAGE_SECTION_HEADER*)(pOptHeader+1),pNTHeader->FileHeader.NumberOfSections,GUICookie); + DumpBaseReloc("Base Relocation Table",&pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC],GUICookie); + DumpIAT("Import Address Table", &pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT],GUICookie); + DumpIAT("Delay Load Import Address Table", &pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT],GUICookie); + } + if(dwAddrOfEntryPoint != 0) DumpEntryPoint(dwAddrOfEntryPoint,dwEntryPointSize,GUICookie); + printLine(GUICookie,""); + printLine(GUICookie,""); + if (!CORHeader) + { + printLine(GUICookie,RstrUTF(IDS_E_COMIMAGE)); + return; + } + strcpy_s(szString,SZSTRING_SIZE,"// ----- CLR Header:"); + printLine(GUICookie,szStr); + + sprintf_s(szString,SZSTRING_SIZE,"// Header size: 0x%08x", VAL32(CORHeader->cb)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Major runtime version: 0x%04x", VAL16(CORHeader->MajorRuntimeVersion)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Minor runtime version: 0x%04x", VAL16(CORHeader->MinorRuntimeVersion)); + printLine(GUICookie,szStr); + // Metadata + DUMP_DIRECTORY("Metadata Directory: ", CORHeader->MetaData); + sprintf_s(szString,SZSTRING_SIZE,"// Flags: 0x%08x", VAL32(CORHeader->Flags)); + printLine(GUICookie,szStr); + sprintf_s(szString,SZSTRING_SIZE,"// Entry point token: 0x%08x", + VAL32(IMAGE_COR20_HEADER_FIELD(*CORHeader, EntryPointToken))); + printLine(GUICookie,szStr); + // Binding + DUMP_DIRECTORY("Resources Directory: ", CORHeader->Resources); + DUMP_DIRECTORY("Strong Name Signature: ", CORHeader->StrongNameSignature); + DUMP_DIRECTORY("CodeManager Table: ", CORHeader->CodeManagerTable); + + // Fixups + DUMP_DIRECTORY("VTableFixups Directory: ", CORHeader->VTableFixups); + DUMP_DIRECTORY("Export Address Table: ", CORHeader->ExportAddressTableJumps); + + // Managed Native Code + DUMP_DIRECTORY("Precompile Header: ", CORHeader->ManagedNativeHeader); + + DumpMetadataHeader("Metadata Header",&(CORHeader->MetaData),GUICookie); +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + + +void DumpHeaderDetails(IMAGE_COR20_HEADER *CORHeader, void* GUICookie) +{ + printLine(GUICookie,""); + DumpCodeManager(CORHeader,GUICookie); + printLine(GUICookie,""); + DumpVTables(CORHeader,GUICookie); + printLine(GUICookie,""); + DumpEATTable(CORHeader,GUICookie); + printLine(GUICookie,""); +} + + +void WritePerfData(const char *KeyDesc, const char *KeyName, const char *UnitDesc, const char *UnitName, void* Value, BOOL IsInt) +{ + + DWORD BytesWritten; + + if(!g_fDumpToPerfWriter) return; + + if (!g_PerfDataFilePtr) + { + if((g_PerfDataFilePtr = WszCreateFile(L"c:\\temp\\perfdata.dat", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL) ) == INVALID_HANDLE_VALUE) + { + printLine(NULL,"PefTimer::LogStoppedTime(): Unable to open the FullPath file. No performance data will be generated"); + g_fDumpToPerfWriter = FALSE; + return; + } + WriteFile(g_PerfDataFilePtr,"ExecTime=0\r\n",13,&BytesWritten,NULL); + WriteFile(g_PerfDataFilePtr,"ExecUnit=bytes\r\n",17,&BytesWritten,NULL); + WriteFile(g_PerfDataFilePtr,"ExecUnitDescr=File Size\r\n",26,&BytesWritten,NULL); + WriteFile(g_PerfDataFilePtr,"ExeciDirection=False\r\n",23,&BytesWritten,NULL); + } + + char ValueStr[10]; + char TmpStr[201]; + + if (IsInt) + { + sprintf_s(ValueStr,10,"%d",(int)*(int*)Value); + } + else + { + sprintf_s(ValueStr,10,"%5.2f",(float)*(float*)Value); + } + sprintf_s(TmpStr, 201, "%s=%s\r\n", KeyName, ValueStr); + WriteFile(g_PerfDataFilePtr, TmpStr, (DWORD)strlen(TmpStr), &BytesWritten, NULL); + + sprintf_s(TmpStr, 201, "%s Descr=%s\r\n", KeyName, KeyDesc); + WriteFile(g_PerfDataFilePtr, TmpStr, (DWORD)strlen(TmpStr), &BytesWritten, NULL); + + sprintf_s(TmpStr, 201, "%s Unit=%s\r\n", KeyName, UnitName); + WriteFile(g_PerfDataFilePtr, TmpStr, (DWORD)strlen(TmpStr), &BytesWritten, NULL); + + sprintf_s(TmpStr, 201, "%s Unit Descr=%s\r\n", KeyName, UnitDesc); + WriteFile(g_PerfDataFilePtr, TmpStr, (DWORD)strlen(TmpStr), &BytesWritten, NULL); + + sprintf_s(TmpStr, 201, "%s IDirection=%s\r\n", KeyName, "False"); + WriteFile(g_PerfDataFilePtr, TmpStr, (DWORD)strlen(TmpStr), &BytesWritten, NULL); +} + +void WritePerfDataInt(const char *KeyDesc, const char *KeyName, const char *UnitDesc, const char *UnitName, int Value) +{ + WritePerfData(KeyDesc,KeyName,UnitDesc,UnitName, (void*)&Value, TRUE); +} +void WritePerfDataFloat(const char *KeyDesc, const char *KeyName, const char *UnitDesc, const char *UnitName, float Value) +{ + WritePerfData(KeyDesc,KeyName,UnitDesc,UnitName, (void*)&Value, FALSE); +} + + +IMetaDataTables *pITables = NULL; +//ULONG sizeRec, count; +//int size, size2; +int metaSize = 0; +__int64 fTableSeen; +inline void TableSeen(unsigned long n) { fTableSeen |= (I64(1) << n); } +inline int IsTableSeen(unsigned long n) { return (fTableSeen & (I64(1) << n)) ? 1 : 0;} +inline void TableSeenReset() { fTableSeen = 0;} + +void DumpTable(unsigned long Table, const char *TableName, void* GUICookie) +{ + char *szStr = &szString[0]; + const char **ppTableName = 0; + int size; + ULONG sizeRec, count; + + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + + // Record that this table has been seen. + TableSeen(Table); + + // If no name passed in, get from table info. + if (!TableName) + ppTableName = &TableName; + + pITables->GetTableInfo(Table, &sizeRec, &count, NULL, NULL, ppTableName); + if(count > 0) + { + metaSize += size = count * sizeRec; + WritePerfDataInt(TableName,TableName,"count","count",count); + WritePerfDataInt(TableName,TableName,"bytes","bytes",size); + sprintf_s(szString,SZSTRING_SIZE,"// %-14s- %4d (%d bytes)", TableName, count, size); + printLine(GUICookie,szStr); + } +} + + + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +void DumpStatistics(IMAGE_COR20_HEADER *CORHeader, void* GUICookie) +{ + int fileSize, miscPESize, miscCOMPlusSize, methodHeaderSize, methodBodySize; + int methodBodies, fatHeaders, tinyHeaders, deprecatedHeaders; + int size, size2; + int fatSections, smallSections; + ULONG methodDefs; + ULONG i; + ULONG sizeRec, count; + char buf[MAX_MEMBER_LENGTH]; + char* szStr = &szString[0]; + if(g_Mode & MODE_GUI) szStr += 2; // no need for "//" in GUI mode + + TableSeenReset(); + metaSize = 0; + + sprintf_s(szString,SZSTRING_SIZE,"// File size : %d", fileSize = SafeGetFileSize(g_pPELoader->getHFile(), NULL)); + printLine(GUICookie,szStr); + + WritePerfDataInt("FileSize","FileSize","standard byte","bytes",fileSize); + + if (g_pPELoader->IsPE32()) + { + size = VAL32(((IMAGE_DOS_HEADER*) g_pPELoader->getHModule())->e_lfanew) + + sizeof(IMAGE_NT_HEADERS32) - sizeof(IMAGE_OPTIONAL_HEADER32) + + VAL16(g_pPELoader->ntHeaders32()->FileHeader.SizeOfOptionalHeader) + + VAL16(g_pPELoader->ntHeaders32()->FileHeader.NumberOfSections) * sizeof(IMAGE_SECTION_HEADER); + size2 = (size + VAL32(g_pPELoader->ntHeaders32()->OptionalHeader.FileAlignment) - 1) & ~(VAL32(g_pPELoader->ntHeaders32()->OptionalHeader.FileAlignment) - 1); + } + else + { + size = VAL32(((IMAGE_DOS_HEADER*) g_pPELoader->getHModule())->e_lfanew) + + sizeof(IMAGE_NT_HEADERS64) - sizeof(IMAGE_OPTIONAL_HEADER64) + + VAL16(g_pPELoader->ntHeaders64()->FileHeader.SizeOfOptionalHeader) + + VAL16(g_pPELoader->ntHeaders64()->FileHeader.NumberOfSections) * sizeof(IMAGE_SECTION_HEADER); + size2 = (size + VAL32(g_pPELoader->ntHeaders64()->OptionalHeader.FileAlignment) - 1) & ~(VAL32(g_pPELoader->ntHeaders64()->OptionalHeader.FileAlignment) - 1); + } + + DWORD sizeOfHeaders; + + if (g_pPELoader->IsPE32()) + { + sizeOfHeaders = VAL32(g_pPELoader->ntHeaders32()->OptionalHeader.SizeOfHeaders); + + WritePerfDataInt("PE header size", "PE header size", "standard byte", "bytes", sizeOfHeaders); + WritePerfDataInt("PE header size used", "PE header size used", "standard byte", "bytes", size); + WritePerfDataFloat("PE header size", "PE header size", "percentage", "percentage", (float)((sizeOfHeaders * 100) / fileSize)); + sprintf_s(szString,SZSTRING_SIZE,"// PE header size : %d (%d used) (%5.2f%%)", + sizeOfHeaders, size, (double) (sizeOfHeaders * 100) / fileSize); + + printLine(GUICookie,szStr); + miscPESize = 0; + + for (i=0; i < VAL32(g_pPELoader->ntHeaders32()->OptionalHeader.NumberOfRvaAndSizes); ++i) + { + // Skip the CLR header. + if (i != 15) miscPESize += (int) VAL32(g_pPELoader->ntHeaders32()->OptionalHeader.DataDirectory[i].Size); + } + } + else + { + sizeOfHeaders = VAL32(g_pPELoader->ntHeaders64()->OptionalHeader.SizeOfHeaders); + + WritePerfDataInt("PE+ header size", "PE header size", "standard byte", "bytes", sizeOfHeaders); + WritePerfDataInt("PE+ header size used", "PE header size used", "standard byte", "bytes", size); + WritePerfDataFloat("PE+ header size", "PE header size", "percentage", "percentage", (float)((sizeOfHeaders * 100) / fileSize)); + + sprintf_s(szString,SZSTRING_SIZE,"// PE header size : %d (%d used) (%5.2f%%)", + sizeOfHeaders, size, (double) (sizeOfHeaders * 100) / fileSize); + + printLine(GUICookie,szStr); + miscPESize = 0; + + for (i=0; i < VAL32(g_pPELoader->ntHeaders64()->OptionalHeader.NumberOfRvaAndSizes); ++i) + { + // Skip the CLR header. + if (i != IMAGE_DIRECTORY_ENTRY_COMHEADER) miscPESize += (int) VAL32(g_pPELoader->ntHeaders64()->OptionalHeader.DataDirectory[i].Size); + } + } + + WritePerfDataInt("PE additional info", "PE additional info", "standard byte", "bytes",miscPESize); + WritePerfDataFloat("PE additional info", "PE additional info", "percentage", "percent", (float) ((miscPESize * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "PE additional info : %d", miscPESize); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (miscPESize * 100) / fileSize); + printLine(GUICookie,szStr); + + WORD numberOfSections; + if (g_pPELoader->IsPE32()) + { + numberOfSections = VAL16(g_pPELoader->ntHeaders32()->FileHeader.NumberOfSections); + } + else + { + numberOfSections = VAL16(g_pPELoader->ntHeaders64()->FileHeader.NumberOfSections); + } + + WritePerfDataInt("Num.of PE sections", "Num.of PE sections", "Nbr of sections", "sections",numberOfSections); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of PE sections : %d", numberOfSections); + + printLine(GUICookie,szStr); + + WritePerfDataInt("CLR header size", "CLR header size", "byte", "bytes",VAL32(CORHeader->cb)); + WritePerfDataFloat("CLR header size", "CLR header size", "percentage", "percent",(float) ((VAL32(CORHeader->cb) * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "CLR header size : %d", VAL32(CORHeader->cb)); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (VAL32(CORHeader->cb) * 100) / fileSize); + printLine(GUICookie,szStr); + + DWORD dwMetaSize = g_cbMetaData; + WritePerfDataInt("CLR meta-data size", "CLR meta-data size", "bytes", "bytes",dwMetaSize); + WritePerfDataFloat("CLR meta-data size", "CLR meta-data size", "percentage", "percent",(float) ((dwMetaSize * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "CLR meta-data size : %d", dwMetaSize); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (dwMetaSize * 100) / fileSize); + printLine(GUICookie,szStr); + + IMAGE_DATA_DIRECTORY *pFirst = &CORHeader->Resources; + ULONG32 iCount = (ULONG32)((BYTE *) &CORHeader->ManagedNativeHeader - (BYTE *) &CORHeader->Resources) / sizeof(IMAGE_DATA_DIRECTORY) + 1; + miscCOMPlusSize = 0; + for (ULONG32 iDir=0; iDir<iCount; iDir++) + { + miscCOMPlusSize += VAL32(pFirst->Size); + pFirst++; + } + + WritePerfDataInt("CLR Additional info", "CLR Additional info", "bytes", "bytes",miscCOMPlusSize); + WritePerfDataFloat("CLR Additional info", "CLR Additional info", "percentage", "percent",(float) ((miscCOMPlusSize * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "CLR additional info : %d", miscCOMPlusSize); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (miscCOMPlusSize * 100) / fileSize); + printLine(GUICookie,szStr); + + // Go through each method def collecting some statistics. + methodHeaderSize = methodBodySize = 0; + methodBodies = fatHeaders = tinyHeaders = deprecatedHeaders = fatSections = smallSections = 0; + methodDefs = g_pImport->GetCountWithTokenKind(mdtMethodDef); + for (i=1; i <= methodDefs; ++i) { + ULONG rva; + DWORD flags; + + if (FAILED(g_pImport->GetMethodImplProps(TokenFromRid(i, mdtMethodDef), &rva, &flags))) + { + continue; + } + if ((rva != 0)&&(IsMiIL(flags) || IsMiOPTIL(flags))) // We don't handle native yet. + { + ++methodBodies; + + COR_ILMETHOD_FAT *pMethod; + g_pPELoader->getVAforRVA(rva, (void **) &pMethod); + if (pMethod->IsFat()) + { + ++fatHeaders; + + methodHeaderSize += pMethod->GetSize() * 4; + methodBodySize += pMethod->GetCodeSize(); + + // Add in the additional sections. + BYTE *sectsBegin = (BYTE *) (pMethod->GetCode() + pMethod->GetCodeSize()); + const COR_ILMETHOD_SECT *pSect = pMethod->GetSect(); + const COR_ILMETHOD_SECT *pOldSect; + if (pSect != NULL) { + // Keep skipping a pointer past each section. + do + { + pOldSect = pSect; + if (((COR_ILMETHOD_SECT_FAT *) pSect)->GetKind() & CorILMethod_Sect_FatFormat) + { + ++fatSections; + pSect = (COR_ILMETHOD_SECT *)((BYTE *) pSect + ((COR_ILMETHOD_SECT_FAT *) pSect)->GetDataSize()); + } + else + { + ++smallSections; + pSect = (COR_ILMETHOD_SECT *)((BYTE *) pSect + ((COR_ILMETHOD_SECT_SMALL *) pSect)->DataSize); + } + pSect = (COR_ILMETHOD_SECT *) (((UINT_PTR) pSect + 3) & ~3); + } + while (pOldSect->More()); + + // Add on the section sizes. + methodHeaderSize += (int) ((BYTE *) pSect - sectsBegin); + } + } + else if (((COR_ILMETHOD_TINY *) pMethod)->IsTiny()) + { + ++tinyHeaders; + methodHeaderSize += sizeof(COR_ILMETHOD_TINY); + methodBodySize += ((COR_ILMETHOD_TINY *) pMethod)->GetCodeSize(); + } + else + { + _ASSERTE(!"Unrecognized header type"); + } + } + } + + + WritePerfDataInt("CLR method headers", "CLR method headers", "bytes", "bytes",methodHeaderSize); + WritePerfDataFloat("CLR method headers", "CLR method headers", "percentage", "percent",(float) ((methodHeaderSize * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "CLR method headers : %d", methodHeaderSize); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (methodHeaderSize * 100) / fileSize); + printLine(GUICookie,szStr); + + WritePerfDataInt("Managed code", "Managed code", "bytes", "bytes",methodBodySize); + WritePerfDataFloat("Managed code", "Managed code", "percentage", "percent",(float) ((methodBodySize * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "Managed code : %d", methodBodySize); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (methodBodySize * 100) / fileSize); + printLine(GUICookie,szStr); + + if (g_pPELoader->IsPE32()) + { + DWORD sizeOfInitializedData = VAL32(g_pPELoader->ntHeaders32()->OptionalHeader.SizeOfInitializedData); + + WritePerfDataInt("Data", "Data", "bytes", "bytes",sizeOfInitializedData); + WritePerfDataFloat("Data", "Data", "percentage", "percent",(float) ((sizeOfInitializedData * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "Data : %d", sizeOfInitializedData); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (sizeOfInitializedData * 100) / fileSize); + printLine(GUICookie,szStr); + + size = fileSize - g_pPELoader->ntHeaders32()->OptionalHeader.SizeOfHeaders - miscPESize - CORHeader->cb - + g_cbMetaData - miscCOMPlusSize - + sizeOfInitializedData - + methodHeaderSize - methodBodySize; + } + else + { + DWORD sizeOfInitializedData = VAL32(g_pPELoader->ntHeaders64()->OptionalHeader.SizeOfInitializedData); + + WritePerfDataInt("Data", "Data", "bytes", "bytes",sizeOfInitializedData); + WritePerfDataFloat("Data", "Data", "percentage", "percent",(float) ((sizeOfInitializedData * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "Data : %d", sizeOfInitializedData); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (sizeOfInitializedData * 100) / fileSize); + printLine(GUICookie,szStr); + + size = fileSize - g_pPELoader->ntHeaders64()->OptionalHeader.SizeOfHeaders - miscPESize - CORHeader->cb - + g_cbMetaData - miscCOMPlusSize - + sizeOfInitializedData - + methodHeaderSize - methodBodySize; + } + + WritePerfDataInt("Unaccounted", "Unaccounted", "bytes", "bytes",size); + WritePerfDataFloat("Unaccounted", "Unaccounted", "percentage", "percent",(float) ((size * 100) / fileSize)); + + sprintf_s(buf, MAX_MEMBER_LENGTH, "Unaccounted : %d", size); + sprintf_s(szString,SZSTRING_SIZE,"// %-40s (%5.2f%%)", buf, (double) (size * 100) / fileSize); + printLine(GUICookie,szStr); + + + // Detail... + if (g_pPELoader->IsPE32()) + { + numberOfSections = VAL16(g_pPELoader->ntHeaders32()->FileHeader.NumberOfSections); + + WritePerfDataInt("Num.of PE sections", "Num.of PE sections", "bytes", "bytes",numberOfSections); + printLine(GUICookie,""); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of PE sections : %d", numberOfSections); + printLine(GUICookie,szStr); + + IMAGE_SECTION_HEADER *pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders32()); + + for (i=0; i < numberOfSections; ++i) + { + WritePerfDataInt((char*)pSecHdr->Name,(char*)pSecHdr->Name, "bytes", "bytes",VAL32(pSecHdr->SizeOfRawData)); + sprintf_s(szString,SZSTRING_SIZE,"// %-8s - %d", pSecHdr->Name, VAL32(pSecHdr->SizeOfRawData)); + printLine(GUICookie,szStr); + ++pSecHdr; + } + } + else + { + numberOfSections = VAL16(g_pPELoader->ntHeaders64()->FileHeader.NumberOfSections); + + WritePerfDataInt("Num.of PE sections", "Num.of PE sections", "bytes", "bytes",numberOfSections); + printLine(GUICookie,""); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of PE sections : %d", numberOfSections); + printLine(GUICookie,szStr); + + IMAGE_SECTION_HEADER *pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders64()); + + for (i=0; i < numberOfSections; ++i) + { + WritePerfDataInt((char*)pSecHdr->Name,(char*)pSecHdr->Name, "bytes", "bytes",pSecHdr->SizeOfRawData); + sprintf_s(szString,SZSTRING_SIZE,"// %-8s - %d", pSecHdr->Name, pSecHdr->SizeOfRawData); + printLine(GUICookie,szStr); + ++pSecHdr; + } + } + + if (FAILED(g_pPubImport->QueryInterface(IID_IMetaDataTables, (void**)&pITables))) + { + sprintf_s(szString,SZSTRING_SIZE,"// Unable to get IMetaDataTables interface"); + printLine(GUICookie,szStr); + return; + } + + if (pITables == 0) + { + printLine(GUICookie,RstrUTF(IDS_E_MDDETAILS)); + return; + } + else + { + DWORD Size = g_cbMetaData; + WritePerfDataInt("CLR meta-data size", "CLR meta-data size", "bytes", "bytes",Size); + printLine(GUICookie,""); + sprintf_s(szString,SZSTRING_SIZE,"// CLR meta-data size : %d", Size); + printLine(GUICookie,szStr); + metaSize = 0; + + pITables->GetTableInfo(TBL_Module, &sizeRec, &count, NULL, NULL, NULL); + TableSeen(TBL_Module); + metaSize += size = count * sizeRec; \ + WritePerfDataInt("Module (count)", "Module (count)", "count", "count",count); + WritePerfDataInt("Module (bytes)", "Module (bytes)", "bytes", "bytes",size); + sprintf_s(szString,SZSTRING_SIZE,"// %-14s- %4d (%d bytes)", "Module", count, size); \ + printLine(GUICookie,szStr); + + if ((count = g_pImport->GetCountWithTokenKind(mdtTypeDef)) > 0) + { + int flags, interfaces = 0, explicitLayout = 0; + for (i=1; i <= count; ++i) + { + if (FAILED(g_pImport->GetTypeDefProps(TokenFromRid(i, mdtTypeDef), (ULONG *) &flags, NULL))) + { + continue; + } + if (flags & tdInterface) ++interfaces; + if (flags & tdExplicitLayout) ++explicitLayout; + } + // Get count from table -- count reported by GetCount... doesn't include the "global" typedef. + pITables->GetTableInfo(TBL_TypeDef, &sizeRec, &count, NULL, NULL, NULL); + TableSeen(TBL_TypeDef); + metaSize += size = count * sizeRec; + + WritePerfDataInt("TypeDef (count)", "TypeDef (count)", "count", "count", count); + WritePerfDataInt("TypeDef (bytes)", "TypeDef (bytes)", "bytes", "bytes", size); + WritePerfDataInt("interfaces", "interfaces", "count", "count", interfaces); + WritePerfDataInt("explicitLayout", "explicitLayout", "count", "count", explicitLayout); + + sprintf_s(buf, MAX_MEMBER_LENGTH, " TypeDef - %4d (%d bytes)", count, size); + sprintf_s(szString,SZSTRING_SIZE,"// %-38s %d interfaces, %d explicit layout", buf, interfaces, explicitLayout); + printLine(GUICookie,szStr); + } + } + + pITables->GetTableInfo(TBL_TypeRef, &sizeRec, &count, NULL, NULL, NULL); + TableSeen(TBL_TypeRef); + if (count > 0) + { + metaSize += size = count * sizeRec; \ + WritePerfDataInt("TypeRef (count)", "TypeRef (count)", "count", "count", count); + WritePerfDataInt("TypeRef (bytes)", "TypeRef (bytes)", "bytes", "bytes", size); + sprintf_s(szString,SZSTRING_SIZE,"// %-14s- %4d (%d bytes)", "TypeRef", count, size); \ + printLine(GUICookie,szStr); + } + + if ((count = g_pImport->GetCountWithTokenKind(mdtMethodDef)) > 0) + { + int flags, abstract = 0, native = 0; + for (i=1; i <= count; ++i) + { + if (FAILED(g_pImport->GetMethodDefProps(TokenFromRid(i, mdtMethodDef), (DWORD *)&flags))) + { + sprintf_s(szString, SZSTRING_SIZE, "// Invalid MethodDef %08X record", TokenFromRid(i, mdtMethodDef)); + printLine(GUICookie, szStr); + return; + } + if (flags & mdAbstract) ++abstract; + } + pITables->GetTableInfo(TBL_Method, &sizeRec, NULL, NULL, NULL, NULL); + TableSeen(TBL_Method); + if (count > 0) + { + metaSize += size = count * sizeRec; + + WritePerfDataInt("MethodDef (count)", "MethodDef (count)", "count", "count", count); + WritePerfDataInt("MethodDef (bytes)", "MethodDef (bytes)", "bytes", "bytes", size); + WritePerfDataInt("abstract", "abstract", "count", "count", abstract); + WritePerfDataInt("native", "native", "count", "count", native); + WritePerfDataInt("methodBodies", "methodBodies", "count", "count", methodBodies); + + sprintf_s(buf, MAX_MEMBER_LENGTH, " MethodDef - %4d (%d bytes)", count, size); + sprintf_s(szString,SZSTRING_SIZE,"// %-38s %d abstract, %d native, %d bodies", buf, abstract, native, methodBodies); + printLine(GUICookie,szStr); + } + } + + if ((count = g_pImport->GetCountWithTokenKind(mdtFieldDef)) > 0) + { + int flags, constants = 0; + + for (i=1; i <= count; ++i) + { + if (FAILED(g_pImport->GetFieldDefProps(TokenFromRid(i, mdtFieldDef), (DWORD *)&flags))) + { + sprintf_s(szString, SZSTRING_SIZE, "// Invalid FieldDef %08X record", TokenFromRid(i, mdtFieldDef)); + printLine(GUICookie, szStr); + return; + } + if ((flags & (fdStatic|fdInitOnly)) == (fdStatic|fdInitOnly)) ++constants; + } + pITables->GetTableInfo(TBL_Field, &sizeRec, NULL, NULL, NULL, NULL); + metaSize += size = count * sizeRec; + + WritePerfDataInt("FieldDef (count)", "FieldDef (count)", "count", "count", count); + WritePerfDataInt("FieldDef (bytes)", "FieldDef (bytes)", "bytes", "bytes", size); + WritePerfDataInt("constant", "constant", "count", "count", constants); + + sprintf_s(buf, MAX_MEMBER_LENGTH, " FieldDef - %4d (%d bytes)", count, size); + sprintf_s(szString,SZSTRING_SIZE,"// %-38s %d constant", buf, constants); + printLine(GUICookie,szStr); + TableSeen(TBL_Field); + } + + DumpTable(TBL_MemberRef, "MemberRef", GUICookie); + DumpTable(TBL_Param, "ParamDef", GUICookie); + DumpTable(TBL_MethodImpl, "MethodImpl", GUICookie); + DumpTable(TBL_Constant, "Constant", GUICookie); + DumpTable(TBL_CustomAttribute, "CustomAttribute", GUICookie); + DumpTable(TBL_FieldMarshal, "NativeType", GUICookie); + DumpTable(TBL_ClassLayout, "ClassLayout", GUICookie); + DumpTable(TBL_FieldLayout, "FieldLayout", GUICookie); + DumpTable(TBL_StandAloneSig, "StandAloneSig", GUICookie); + DumpTable(TBL_InterfaceImpl, "InterfaceImpl", GUICookie); + DumpTable(TBL_PropertyMap, "PropertyMap", GUICookie); + DumpTable(TBL_Property, "Property", GUICookie); + DumpTable(TBL_MethodSemantics, "MethodSemantic", GUICookie); + DumpTable(TBL_DeclSecurity, "Security", GUICookie); + DumpTable(TBL_TypeSpec, "TypeSpec", GUICookie); + DumpTable(TBL_ModuleRef, "ModuleRef", GUICookie); + DumpTable(TBL_Assembly, "Assembly", GUICookie); + DumpTable(TBL_AssemblyProcessor, "AssemblyProcessor", GUICookie); + DumpTable(TBL_AssemblyOS, "AssemblyOS", GUICookie); + DumpTable(TBL_AssemblyRef, "AssemblyRef", GUICookie); + DumpTable(TBL_AssemblyRefProcessor, "AssemblyRefProcessor", GUICookie); + DumpTable(TBL_AssemblyRefOS, "AssemblyRefOS", GUICookie); + DumpTable(TBL_File, "File", GUICookie); + DumpTable(TBL_ExportedType, "ExportedType", GUICookie); + DumpTable(TBL_ManifestResource, "ManifestResource", GUICookie); + DumpTable(TBL_NestedClass, "NestedClass", GUICookie); + + // Rest of the tables. + pITables->GetNumTables(&count); + for (i=0; i<count; ++i) + { + if (!IsTableSeen(i)) + DumpTable(i, NULL, GUICookie); + } + + // String heap + pITables->GetStringHeapSize(&sizeRec); + if (sizeRec > 0) + { + metaSize += sizeRec; + WritePerfDataInt("Strings", "Strings", "bytes", "bytes",sizeRec); + sprintf_s(szString,SZSTRING_SIZE,"// Strings - %5d bytes", sizeRec); + printLine(GUICookie,szStr); + } + // Blob heap + pITables->GetBlobHeapSize(&sizeRec); + if (sizeRec > 0) + { + metaSize += sizeRec; + WritePerfDataInt("Blobs", "Blobs", "bytes", "bytes",sizeRec); + sprintf_s(szString,SZSTRING_SIZE,"// Blobs - %5d bytes", sizeRec); + printLine(GUICookie,szStr); + } + // User String Heap + pITables->GetUserStringHeapSize(&sizeRec); + if (sizeRec > 0) + { + metaSize += sizeRec; + WritePerfDataInt("UserStrings", "UserStrings", "bytes", "bytes",sizeRec); + sprintf_s(szString,SZSTRING_SIZE,"// UserStrings - %5d bytes", sizeRec); + printLine(GUICookie,szStr); + } + // Guid heap + pITables->GetGuidHeapSize(&sizeRec); + if (sizeRec > 0) + { + metaSize += sizeRec; + WritePerfDataInt("Guids", "Guids", "bytes", "bytes", sizeRec); + sprintf_s(szString,SZSTRING_SIZE,"// Guids - %5d bytes", sizeRec); + printLine(GUICookie,szStr); + } + + if (g_cbMetaData - metaSize > 0) + { + WritePerfDataInt("Uncategorized", "Uncategorized", "bytes", "bytes",g_cbMetaData - metaSize); + sprintf_s(szString,SZSTRING_SIZE,"// Uncategorized - %5d bytes", g_cbMetaData - metaSize); + printLine(GUICookie,szStr); + } + + if (miscCOMPlusSize != 0) + { + WritePerfDataInt("CLR additional info", "CLR additional info", "bytes", "bytes", miscCOMPlusSize); + sprintf_s(szString,SZSTRING_SIZE,"// CLR additional info : %d", miscCOMPlusSize); + printLine(GUICookie,""); + printLine(GUICookie,szStr); + + if (CORHeader->CodeManagerTable.Size != 0) + { + WritePerfDataInt("CodeManagerTable", "CodeManagerTable", "bytes", "bytes", VAL32(CORHeader->CodeManagerTable.Size)); + sprintf_s(szString,SZSTRING_SIZE,"// CodeManagerTable - %d", VAL32(CORHeader->CodeManagerTable.Size)); + printLine(GUICookie,szStr); + } + + if (CORHeader->VTableFixups.Size != 0) + { + WritePerfDataInt("VTableFixups", "VTableFixups", "bytes", "bytes", VAL32(CORHeader->VTableFixups.Size)); + sprintf_s(szString,SZSTRING_SIZE,"// VTableFixups - %d", VAL32(CORHeader->VTableFixups.Size)); + printLine(GUICookie,szStr); + } + + if (CORHeader->Resources.Size != 0) + { + WritePerfDataInt("Resources", "Resources", "bytes", "bytes", VAL32(CORHeader->Resources.Size)); + sprintf_s(szString,SZSTRING_SIZE,"// Resources - %d", VAL32(CORHeader->Resources.Size)); + printLine(GUICookie,szStr); + } + } + WritePerfDataInt("CLR method headers", "CLR method headers", "count", "count", methodHeaderSize); + sprintf_s(szString,SZSTRING_SIZE,"// CLR method headers : %d", methodHeaderSize); + printLine(GUICookie,""); + printLine(GUICookie,szStr); + WritePerfDataInt("Num.of method bodies", "Num.of method bodies", "count", "count",methodBodies); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of method bodies - %d", methodBodies); + printLine(GUICookie,szStr); + WritePerfDataInt("Num.of fat headers", "Num.of fat headers", "count", "count", fatHeaders); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of fat headers - %d", fatHeaders); + printLine(GUICookie,szStr); + WritePerfDataInt("Num.of tiny headers", "Num.of tiny headers", "count", "count", tinyHeaders); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of tiny headers - %d", tinyHeaders); + printLine(GUICookie,szStr); + + if (deprecatedHeaders > 0) { + WritePerfDataInt("Num.of old headers", "Num.of old headers", "count", "count", deprecatedHeaders); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of old headers - %d", deprecatedHeaders); + printLine(GUICookie,szStr); + } + + if (fatSections != 0 || smallSections != 0) { + WritePerfDataInt("Num.of fat sections", "Num.of fat sections", "count", "count", fatSections); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of fat sections - %d", fatSections); + printLine(GUICookie,szStr); + + WritePerfDataInt("Num.of small section", "Num.of small section", "count", "count", smallSections); + sprintf_s(szString,SZSTRING_SIZE,"// Num.of small sections - %d", smallSections); + printLine(GUICookie,szStr); + } + + WritePerfDataInt("Managed code", "Managed code", "bytes", "bytes", methodBodySize); + sprintf_s(szString,SZSTRING_SIZE,"// Managed code : %d", methodBodySize); + printLine(GUICookie,""); + printLine(GUICookie,szStr); + + if (methodBodies != 0) { + WritePerfDataInt("Ave method size", "Ave method size", "bytes", "bytes", methodBodySize / methodBodies); + sprintf_s(szString,SZSTRING_SIZE,"// Ave method size - %d", methodBodySize / methodBodies); + printLine(GUICookie,szStr); + } + + if (pITables) + pITables->Release(); + + if(g_fDumpToPerfWriter) + CloseHandle((char*) g_PerfDataFilePtr); +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +void DumpHexbytes(__inout __nullterminated char* szString,BYTE *pb, DWORD fromPtr, DWORD toPtr, DWORD limPtr) +{ + char sz[256]; + char* szptr = &szString[strlen(szString)]; + int k = 0,i; + DWORD curPtr = 0; + bool printsz = FALSE; + BYTE zero = 0; + *szptr = 0; + for(i = 0,k = 0,curPtr=fromPtr; curPtr < toPtr; i++,k++,curPtr++,pb++) + { + + if(k == 16) + { + if(printsz) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(" // %s"),sz); + printLine(g_pFile,szString); + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s ",g_szAsmCodeIndent); + k = 0; + printsz = FALSE; + } + if(curPtr >= limPtr) pb = &zero; // at limPtr and after, pad with 0 + else + { + WIN_PAL_CPP_TRY + { + sz[k] = *pb; // check the ptr validity + } + WIN_PAL_CPP_CATCH_ALL + { + pb = &zero; + } WIN_PAL_CPP_ENDTRY; + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %2.2X", *pb); + if(isprint(*pb)) + { + if(g_fDumpRTF) + { + if((*pb == '\\')||(*pb=='{')||(*pb=='}')) sz[k++]='\\'; + sz[k] = *pb; + } + else if(g_fDumpHTML) + { + if(*pb == '<') { sz[k] = 0; strcat_s(sz,256-k,LTN()); k+=(int)(strlen(LTN())); } + else if(*pb == '>') { sz[k] = 0; strcat_s(sz,256-k,GTN()); k+=(int)(strlen(GTN())); } + } + else sz[k] = *pb; + printsz = TRUE; + } + else + { + sz[k] = '.'; + } + sz[k+1] = 0; + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),") "); + if(printsz) + { + for(i = k; i < 16; i++) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," "); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// %s"),sz); + } + printLine(g_pFile,szString); +} + +struct VTableEntry +{ + DWORD dwAddr; + WORD wCount; + WORD wType; +}; + +struct ExpDirTable +{ + DWORD dwFlags; + DWORD dwDateTime; + WORD wVMajor; + WORD wVMinor; + DWORD dwNameRVA; + DWORD dwOrdinalBase; + DWORD dwNumATEntries; + DWORD dwNumNamePtrs; + DWORD dwAddrTableRVA; + DWORD dwNamePtrRVA; + DWORD dwOrdTableRVA; +}; + +void DumpEATEntries(void* GUICookie, + IMAGE_NT_HEADERS32 *pNTHeader32, IMAGE_OPTIONAL_HEADER32 *pOptHeader32, + IMAGE_NT_HEADERS64 *pNTHeader64, IMAGE_OPTIONAL_HEADER64 *pOptHeader64) +{ + IMAGE_DATA_DIRECTORY *pExportDir = NULL; + IMAGE_SECTION_HEADER *pSecHdr = NULL; + DWORD i,j,N; + BOOL bpOpt = FALSE; + + if (g_pPELoader->IsPE32()) + { + pExportDir = pOptHeader32->DataDirectory; + pSecHdr = IMAGE_FIRST_SECTION(pNTHeader32); + N = VAL16(pNTHeader32->FileHeader.NumberOfSections); + + if (pOptHeader32->NumberOfRvaAndSizes) + bpOpt = TRUE; + } + else + { + pExportDir = pOptHeader64->DataDirectory; + pSecHdr = IMAGE_FIRST_SECTION(pNTHeader64); + N = VAL16(pNTHeader64->FileHeader.NumberOfSections); + + if (pOptHeader64->NumberOfRvaAndSizes) + bpOpt = TRUE; + + } + if(bpOpt) + { + ExpDirTable *pExpTable = NULL; + if(pExportDir->Size) + { +#ifdef _DEBUG + printLine(GUICookie,COMMENT((char*)0)); // start multiline comment + sprintf_s(szString,SZSTRING_SIZE,"// Export dir VA=%X size=%X ",VAL32(pExportDir->VirtualAddress),VAL32(pExportDir->Size)); + printLine(GUICookie,szString); +#endif + DWORD vaExpTable = VAL32(pExportDir->VirtualAddress); + for (i=0; i < N; i++,pSecHdr++) + { + if((vaExpTable >= VAL32(pSecHdr->VirtualAddress))&& + (vaExpTable < VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize))) + { + pExpTable = (ExpDirTable*)( g_pPELoader->base() + + VAL32(pSecHdr->PointerToRawData) + + vaExpTable - VAL32(pSecHdr->VirtualAddress)); +#ifdef _DEBUG + sprintf_s(szString,SZSTRING_SIZE,"// in section '%s': VA=%X Misc.VS=%X PRD=%X ",(char*)(pSecHdr->Name), + VAL32(pSecHdr->VirtualAddress),VAL32(pSecHdr->Misc.VirtualSize),VAL32(pSecHdr->PointerToRawData)); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// Export Directory Table:"); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwFlags = %X",VAL32(pExpTable->dwFlags)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwDateTime = %X",VAL32(pExpTable->dwDateTime)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// wVMajor = %X",VAL16(pExpTable->wVMajor)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// wVMinor = %X",VAL16(pExpTable->wVMinor)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwNameRVA = %X",VAL32(pExpTable->dwNameRVA)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwOrdinalBase = %X",VAL32(pExpTable->dwOrdinalBase)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwNumATEntries = %X",VAL32(pExpTable->dwNumATEntries)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwNumNamePtrs = %X",VAL32(pExpTable->dwNumNamePtrs)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwAddrTableRVA = %X",VAL32(pExpTable->dwAddrTableRVA)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwNamePtrRVA = %X",VAL32(pExpTable->dwNamePtrRVA)); printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"// dwOrdTableRVA = %X",VAL32(pExpTable->dwOrdTableRVA)); printLine(GUICookie,szString); + if(pExpTable->dwNameRVA) + { + char* szName; + if(g_pPELoader->getVAforRVA(VAL32(pExpTable->dwNameRVA), (void **) &szName)) + sprintf_s(szString,SZSTRING_SIZE,"// DLL Name: '%s'",szName); + else + sprintf_s(szString,SZSTRING_SIZE,"// DLL Name: BAD RVA: 0x%8.8X",VAL32(pExpTable->dwNameRVA)); + + printLine(GUICookie,szString); + } +#endif + if(pExpTable->dwNumATEntries && pExpTable->dwAddrTableRVA) + { + DWORD* pExpAddr; + BYTE *pCont; + DWORD dwTokRVA; + mdToken* pTok; + g_pPELoader->getVAforRVA(VAL32(pExpTable->dwAddrTableRVA), (void **) &pExpAddr); +#ifdef _DEBUG + sprintf_s(szString,SZSTRING_SIZE,"// Export Address Table:"); printLine(GUICookie,szString); +#endif + g_nEATableRef = VAL32(pExpTable->dwNumATEntries); + if (g_prEATableRef == NULL) + { + g_prEATableRef = new DynamicArray<EATableRef>; + } + + (*g_prEATableRef)[g_nEATableRef].tkTok = 0; // to avoid multiple reallocations of DynamicArray + for(j=0; j < VAL32(pExpTable->dwNumATEntries); j++,pExpAddr++) + { + g_pPELoader->getVAforRVA(VAL32(*pExpAddr), (void **) &pCont); +#ifdef _DEBUG + sprintf_s(szString,SZSTRING_SIZE,"// [%d]: RVA=%X VA=%p(",j,VAL32(*pExpAddr),pCont); + DumpByteArray(szString,pCont,16,GUICookie); + printLine(GUICookie,szString); +#endif + (*g_prEATableRef)[j].tkTok = 0; + + if(g_pPELoader->IsPE32()) + { + dwTokRVA = VAL32(*((DWORD*)(pCont+2))); // first two bytes - JumpIndirect (0x25FF) + dwTokRVA -= VAL32((DWORD)pOptHeader32->ImageBase); + } + else + { + ULONGLONG ullTokRVA; + if(pNTHeader64->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64) + ullTokRVA = VAL64(*((ULONGLONG*)(pCont+8))); + else + ullTokRVA = VAL64(*((ULONGLONG*)(pCont+2))); + + dwTokRVA =(DWORD)(ullTokRVA - VAL64((DWORD)pOptHeader64->ImageBase)); + } + if(g_pPELoader->getVAforRVA(dwTokRVA,(void**)&pTok)) + (*g_prEATableRef)[j].tkTok = VAL32(*pTok); + + (*g_prEATableRef)[j].pszName = NULL; + + } + } + if(pExpTable->dwNumNamePtrs && pExpTable->dwNamePtrRVA && pExpTable->dwOrdTableRVA) + { + DWORD *pNamePtr; + WORD *pOrd; + char* szName; + g_pPELoader->getVAforRVA(VAL32(pExpTable->dwNamePtrRVA), (void **) &pNamePtr); + g_pPELoader->getVAforRVA(VAL32(pExpTable->dwOrdTableRVA), (void **) &pOrd); +#ifdef _DEBUG + sprintf_s(szString,SZSTRING_SIZE,"// Export Names:"); printLine(GUICookie,szString); +#endif + for(j=0; j < VAL32(pExpTable->dwNumATEntries); j++,pNamePtr++,pOrd++) + { + g_pPELoader->getVAforRVA(VAL32(*pNamePtr), (void **) &szName); +#ifdef _DEBUG + sprintf_s(szString,SZSTRING_SIZE,"// [%d]: NamePtr=%X Ord=%X Name='%s'",j,VAL32(*pNamePtr),*pOrd,szName); + printLine(GUICookie,szString); +#endif + (*g_prEATableRef)[VAL16(*pOrd)].pszName = szName; + } + } + g_nEATableBase = pExpTable->dwOrdinalBase; + break; + } + } +#ifdef _DEBUG + printLine(GUICookie,COMMENT((char*)-1)); // end multiline comment +#endif + } + } +} +// helper to avoid mixing of SEH and stack objects with destructors +void DumpEATEntriesWrapper(void* GUICookie, + IMAGE_NT_HEADERS32 *pNTHeader32, IMAGE_OPTIONAL_HEADER32 *pOptHeader32, + IMAGE_NT_HEADERS64 *pNTHeader64, IMAGE_OPTIONAL_HEADER64 *pOptHeader64) +{ + WIN_PAL_CPP_TRY + { + DumpEATEntries(GUICookie, pNTHeader32, pOptHeader32, pNTHeader64, pOptHeader64); + } + WIN_PAL_CPP_CATCH_ALL + { + printError(GUICookie,"// ERROR READING EXPORT ADDRESS TABLE"); + if (g_prEATableRef != NULL) + { + SDELETE(g_prEATableRef); + } + g_nEATableRef = 0; + } + WIN_PAL_CPP_ENDTRY +} + +void DumpVtable(void* GUICookie) +{ + // VTable : primary processing + DWORD pVTable=0; + VTableEntry* pVTE; + DWORD i,j,k; + char* szptr; + + IMAGE_NT_HEADERS32 *pNTHeader32 = NULL; + IMAGE_OPTIONAL_HEADER32 *pOptHeader32 = NULL; + + IMAGE_NT_HEADERS64 *pNTHeader64 = NULL; + IMAGE_OPTIONAL_HEADER64 *pOptHeader64 = NULL; + + if (g_pPELoader->IsPE32()) + { + pNTHeader32 = g_pPELoader->ntHeaders32(); + pOptHeader32 = &pNTHeader32->OptionalHeader; + + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%08x", g_szAsmCodeIndent,KEYWORD(".imagebase"),VAL32(pOptHeader32->ImageBase)); + printLine(GUICookie,szString); + j = VAL16(pOptHeader32->Subsystem); + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%08x", g_szAsmCodeIndent,KEYWORD(".file alignment"),VAL32(pOptHeader32->FileAlignment)); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%08x", g_szAsmCodeIndent,KEYWORD(".stackreserve"),VAL32(pOptHeader32->SizeOfStackReserve)); + printLine(GUICookie,szString); + } + else + { + pNTHeader64 = g_pPELoader->ntHeaders64(); + pOptHeader64 = &pNTHeader64->OptionalHeader; + + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%016I64x", g_szAsmCodeIndent,KEYWORD(".imagebase"),VAL64(pOptHeader64->ImageBase)); + printLine(GUICookie,szString); + j = VAL16(pOptHeader64->Subsystem); + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%08x", g_szAsmCodeIndent,KEYWORD(".file alignment"),VAL32(pOptHeader64->FileAlignment)); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%016I64x", g_szAsmCodeIndent,KEYWORD(".stackreserve"),VAL64(pOptHeader64->SizeOfStackReserve)); + printLine(GUICookie,szString); + } + szptr = &szString[0]; + szptr += sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%04x", g_szAsmCodeIndent,KEYWORD(".subsystem"),j); + { + char* psz[15] = {"// UNKNOWN", + "// NATIVE", + "// WINDOWS_GUI", + "// WINDOWS_CUI", + "// <illegal value>", + "// OS2_CUI", + "// <illegal value>", + "// POSIX_CUI", + "// NATIVE_WINDOWS", + "// WINDOWS_CE_GUI", + "// EFI_APPLICATION", + "// EFI_BOOT_SERVICE_DRIVER", + "// EFI_RUNTIME_DRIVER", + "// EFI_ROM", + "// XBOX" + }; + if(j > 14) j = 4; // <illegal value> + sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %s",COMMENT(psz[j])); + } + printLine(GUICookie,szString); + + szptr = &szString[0]; + i = (DWORD)VAL32(g_CORHeader->Flags); + szptr += sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%08x", g_szAsmCodeIndent,KEYWORD(".corflags"),i); + if(i != 0) + { + char sz[256], *szp = sz; + szp += sprintf_s(szp,256," // "); + if(i & COMIMAGE_FLAGS_ILONLY) szp += sprintf_s(szp,256-(szp-sz)," ILONLY"); + if(COR_IS_32BIT_REQUIRED(i)) + szp += sprintf_s(szp,256-(szp-sz)," 32BITREQUIRED"); + if(COR_IS_32BIT_PREFERRED(i)) + szp += sprintf_s(szp,256-(szp-sz)," 32BITPREFERRED"); + if(i & COMIMAGE_FLAGS_IL_LIBRARY) szp += sprintf_s(szp,256-(szp-sz)," IL_LIBRARY"); + if(i & COMIMAGE_FLAGS_TRACKDEBUGDATA) szp += sprintf_s(szp,256-(szp-sz)," TRACKDEBUGDATA"); + szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(sz)); + } + printLine(GUICookie,szString); + + sprintf_s(szString,SZSTRING_SIZE,"%s// Image base: 0x%p",g_szAsmCodeIndent,g_pPELoader->base()); + printLine(GUICookie,COMMENT(szString)); + + DumpEATEntriesWrapper(GUICookie, pNTHeader32, pOptHeader32, pNTHeader64, pOptHeader64); + + g_nVTableRef = 0; + if(VAL32(g_CORHeader->VTableFixups.Size)) + { + IMAGE_SECTION_HEADER *pSecHdr = NULL; + DWORD dwNumberOfSections; + + if (g_pPELoader->IsPE32()) + { + pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders32()); + dwNumberOfSections = VAL16(g_pPELoader->ntHeaders32()->FileHeader.NumberOfSections); + } + else + { + pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders64()); + dwNumberOfSections = VAL16(g_pPELoader->ntHeaders64()->FileHeader.NumberOfSections); + } + + pVTable = VAL32(g_CORHeader->VTableFixups.VirtualAddress); + + for (i=0; i < dwNumberOfSections; i++,pSecHdr++) + { + if(((DWORD)pVTable >= VAL32(pSecHdr->VirtualAddress))&& + ((DWORD)pVTable < VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize))) + { + pVTE = (VTableEntry*)( g_pPELoader->base() + + VAL32(pSecHdr->PointerToRawData) + + pVTable - VAL32(pSecHdr->VirtualAddress)); + for(j=VAL32(g_CORHeader->VTableFixups.Size),k=0; j > 0; pVTE++, j-=sizeof(VTableEntry),k++) + { + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s [%d] ",g_szAsmCodeIndent,KEYWORD(".vtfixup"),VAL16(pVTE->wCount)); + DWORD dwSize = VAL16(pVTE->wCount) * 4; + WORD wType = VAL16(pVTE->wType); + if(wType & COR_VTABLE_32BIT) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("int32 ")); + else if(wType & COR_VTABLE_64BIT) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("int64 ")); + dwSize <<= 1; + } + if(wType & COR_VTABLE_FROM_UNMANAGED) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("fromunmanaged ")); + if(wType & COR_VTABLE_CALL_MOST_DERIVED) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("callmostderived ")); + if(wType & 0x8 /*COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN*/) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("retainappdomain ")); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("at ")); + szptr = DumpDataPtr(szptr,VAL32(pVTE->dwAddr), dwSize); + // Walk every v-table fixup entry and dump the slots. + { + BYTE *pSlot; + if (g_pPELoader->getVAforRVA(VAL32(pVTE->dwAddr), (void **) &pSlot)) + { + char* szptr0 = szptr; + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," //"); + for (WORD iSlot=0; iSlot<VAL16(pVTE->wCount); iSlot++) + { + mdMethodDef tkMethod = VAL32(*(DWORD *) pSlot); + if (VAL16(pVTE->wType) & COR_VTABLE_32BIT) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %08X", VAL32(*(DWORD *)pSlot)); + pSlot += sizeof(DWORD); + } + else + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %016I64X", VAL64(*(unsigned __int64 *)pSlot)); + pSlot += sizeof(unsigned __int64); + } + if (g_prVTableRef == NULL) + { + g_prVTableRef = new DynamicArray<VTableRef>; + } + (*g_prVTableRef)[g_nVTableRef].tkTok = tkMethod; + (*g_prVTableRef)[g_nVTableRef].wEntry = (WORD)k; + (*g_prVTableRef)[g_nVTableRef].wSlot = iSlot; + g_nVTableRef++; + + //ValidateToken(tkMethod, mdtMethodDef); + } + sprintf_s(szptr0,SZSTRING_REMAINING_SIZE(szptr0),COMMENT(szptr0)); + } + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %s",ERRORMSG(RstrUTF(IDS_E_BOGUSRVA))); + } + printLine(GUICookie,szString); + } + break; + } + } + } +} +// MetaInfo integration: +void DumpMI(__in __nullterminated const char *str) +{ + static BOOL fInit = TRUE; + static char* szStr = &szString[0]; + static void* GUICookie; + char* pch; + // Reset + if(str == (char*)-1) + { + fInit = TRUE; + return; + } + // Init + if(fInit) + { + strcpy_s(szString,5,"// "); + fInit = FALSE; + GUICookie = (void*)str; + if(g_Mode & MODE_GUI) szStr = &szString[3]; // don't need "//" in GUI mode + return; + } + // Normal work + strcat_s(szString,SZSTRING_SIZE,str); + if((pch = strchr(szStr,'\n'))) + { + *pch = 0; + printLine(GUICookie,szStr); + pch++; + memcpy(&szString[3], pch, strlen(pch)+1); + } +} + +HRESULT VEHandlerReporter( // Return status. + LPCWSTR szMsg, // Error message. + VEContext Context, // Error context (offset,token) + HRESULT hrRpt) // HRESULT for the message +{ + WCHAR* wzMsg; + if(szMsg) + { + size_t L = wcslen(szMsg)+256; + if(wzMsg = new (nothrow) WCHAR[L]) + { + wcscpy_s(wzMsg,L,szMsg); + // include token and offset from Context + if(Context.Token) swprintf_s(&wzMsg[wcslen(wzMsg)], L-wcslen(wzMsg), L" [token:0x%08X]",Context.Token); + if(Context.uOffset) swprintf_s(&wzMsg[wcslen(wzMsg)], L-wcslen(wzMsg), L" [at:0x%X]",Context.uOffset); + swprintf_s(&wzMsg[wcslen(wzMsg)], L-wcslen(wzMsg), L" [hr:0x%08X]\n",hrRpt); + DumpMI(UnicodeToUtf(wzMsg)); + delete[] wzMsg; + } + } + return S_OK; +} + +void DumpMetaInfo(__in __nullterminated const WCHAR* pwzFileName, __in_opt __nullterminated const char* pszObjFileName, void* GUICookie) +{ + const WCHAR* pch = wcsrchr(pwzFileName,L'.'); + + DumpMI((char*)GUICookie); // initialize the print function for DumpMetaInfo + + if(pch && (!_wcsicmp(pch+1,L"lib") || !_wcsicmp(pch+1,L"obj"))) + { // This works only when all the rest does not + // Init and run. + if(SUCCEEDED(CoInitialize(0))) + { + if(SUCCEEDED(LegacyActivationShim::CoInitializeCor(0))) + { + if (SUCCEEDED(LegacyActivationShim::ClrCoCreateInstance( + CLSID_CorMetaDataDispenser, NULL, CLSCTX_INPROC_SERVER, + IID_IMetaDataDispenserEx, (void **) &g_pDisp))) + { + WCHAR *pwzObjFileName=NULL; + if (pszObjFileName) + { + int nLength = (int) strlen(pszObjFileName)+1; + pwzObjFileName = new WCHAR[nLength]; + memset(pwzObjFileName,0,sizeof(WCHAR)*nLength); + WszMultiByteToWideChar(CP_UTF8,0,pszObjFileName,-1,pwzObjFileName,nLength); + } + DisplayFile((wchar_t*)pwzFileName, true, g_ulMetaInfoFilter, pwzObjFileName, DumpMI); + g_pDisp->Release(); + g_pDisp = NULL; + if (pwzObjFileName) VDELETE(pwzObjFileName); + } + LegacyActivationShim::CoUninitializeCor(); + } + CoUninitialize(); + } + } + else + { + HRESULT hr = S_OK; + if(g_pDisp == NULL) + { + hr = LegacyActivationShim::ClrCoCreateInstance( + CLSID_CorMetaDataDispenser, NULL, CLSCTX_INPROC_SERVER, + IID_IMetaDataDispenserEx, (void **) &g_pDisp); + } + if(SUCCEEDED(hr)) + { + g_ValModuleType = ValidatorModuleTypePE; + if(g_pAssemblyImport==NULL) g_pAssemblyImport = GetAssemblyImport(NULL); + if(!(g_Mode & MODE_GUI)) + printLine(GUICookie,RstrUTF(IDS_E_MISTART)); + //MDInfo metaDataInfo(g_pPubImport, g_pAssemblyImport, (LPCWSTR)pwzFileName, DumpMI, g_ulMetaInfoFilter); + MDInfo metaDataInfo(g_pDisp,(LPCWSTR)pwzFileName, DumpMI, g_ulMetaInfoFilter); + metaDataInfo.SetVEHandlerReporter((__int64) (size_t) VEHandlerReporter); + metaDataInfo.DisplayMD(); + if(!(g_Mode & MODE_GUI)) + printLine(GUICookie,RstrUTF(IDS_E_MIEND)); + } + } + DumpMI((char*)-1); // reset the print function for DumpMetaInfo +} + +void DumpPreamble() +{ + printLine(g_pFile,""); + if(g_fDumpHTML) + { + printLine(g_pFile, "<FONT SIZE=4><B>"); + } + else if(g_fDumpRTF) + { + } + sprintf_s(szString,SZSTRING_SIZE,"// Microsoft (R) .NET Framework IL Disassembler. Version " VER_FILEVERSION_STR); + printLine(g_pFile,COMMENT(szString)); + if(g_fDumpHTML) + { + printLine(g_pFile, "</B></FONT>"); + } + else if(g_fDumpRTF) + { + } + printLine(g_pFile,""); + if(g_fLimitedVisibility || (!g_fShowCA) || (!g_fDumpAsmCode) + || (g_Mode & (MODE_DUMP_CLASS | MODE_DUMP_CLASS_METHOD | MODE_DUMP_CLASS_METHOD_SIG))) + { + printLine(g_pFile,""); + printLine(g_pFile,COMMENT(RstrUTF(IDS_E_PARTDASM))); + printLine(g_pFile,""); + } + + if(g_fLimitedVisibility) + { + strcpy_s(szString, SZSTRING_SIZE, RstrUTF(IDS_E_ONLYITEMS)); + if(!g_fHidePub) strcat_s(szString, SZSTRING_SIZE," Public"); + if(!g_fHidePriv) strcat_s(szString, SZSTRING_SIZE," Private"); + if(!g_fHideFam) strcat_s(szString, SZSTRING_SIZE," Family"); + if(!g_fHideAsm) strcat_s(szString, SZSTRING_SIZE," Assembly"); + if(!g_fHideFAA) strcat_s(szString, SZSTRING_SIZE," FamilyANDAssembly"); + if(!g_fHidePrivScope) strcat_s(szString, SZSTRING_SIZE," PrivateScope"); + printLine(g_pFile,COMMENT(szString)); + } +} + +void DumpSummary() +{ + HRESULT hr; + ULONG i; + const char *pcClass,*pcNS,*pcMember, *pcSig; + char szFQN[4096]; + HENUMInternal hEnum; + mdToken tkMember; + CQuickBytes qbMemberSig; + PCCOR_SIGNATURE pComSig; + ULONG cComSig; + DWORD dwAttrs; + mdToken tkEventType; + + printLine(g_pFile,"//============ S U M M A R Y ================================="); + if (SUCCEEDED(g_pImport->EnumGlobalFunctionsInit(&hEnum))) + { + while(g_pImport->EnumNext(&hEnum, &tkMember)) + { + if (FAILED(g_pImport->GetNameOfMethodDef(tkMember, &pcMember)) || + FAILED(g_pImport->GetSigOfMethodDef(tkMember, &cComSig, &pComSig))) + { + sprintf_s(szString, SZSTRING_SIZE, "// ERROR in the method record %08X", tkMember); + printLine(g_pFile, szString); + continue; + } + qbMemberSig.Shrink(0); + pcSig = cComSig ? PrettyPrintSig(pComSig, cComSig, "", &qbMemberSig, g_pImport,NULL) : "NO SIGNATURE"; + PREFIX_ASSUME(ProperName((char*)pcMember) != 0); + sprintf_s(szString,SZSTRING_SIZE,"// %08X [GLM] %s : %s", tkMember,ProperName((char*)pcMember),pcSig); + printLine(g_pFile,szString); + } + } + g_pImport->EnumClose(&hEnum); + if (SUCCEEDED(g_pImport->EnumGlobalFieldsInit(&hEnum))) + { + while(g_pImport->EnumNext(&hEnum, &tkMember)) + { + if (FAILED(g_pImport->GetNameOfFieldDef(tkMember, &pcMember)) || + FAILED(g_pImport->GetSigOfFieldDef(tkMember, &cComSig, &pComSig))) + { + sprintf_s(szString, SZSTRING_SIZE, "// ERROR in the field record %08X", tkMember); + printLine(g_pFile, szString); + continue; + } + qbMemberSig.Shrink(0); + pcSig = cComSig ? PrettyPrintSig(pComSig, cComSig, "", &qbMemberSig, g_pImport,NULL) : "NO SIGNATURE"; + PREFIX_ASSUME(ProperName((char*)pcMember) != 0); + sprintf_s(szString,SZSTRING_SIZE,"// %08X [GLF] %s : %s", tkMember,ProperName((char*)pcMember),pcSig); + printLine(g_pFile,szString); + } + } + g_pImport->EnumClose(&hEnum); + + for (i = 0; i < g_NumClasses; i++) + { + if (FAILED(g_pImport->GetNameOfTypeDef(g_cl_list[i], &pcClass, &pcNS))) + { + sprintf_s(szString, SZSTRING_SIZE, "// ERROR in the TypeDef record %08X", g_cl_list[i]); + printLine(g_pFile, szString); + continue; + } + PREFIX_ASSUME(ProperName((char*)pcClass) != 0); + if(*pcNS) sprintf_s(szFQN,4096,"%s.%s", ProperName((char*)pcNS),ProperName((char*)pcClass)); + else strcpy_s(szFQN,4096,ProperName((char*)pcClass)); + sprintf_s(szString,SZSTRING_SIZE,"// %08X [CLS] %s", g_cl_list[i],szFQN); + printLine(g_pFile,szString); + if(SUCCEEDED(g_pImport->EnumInit(mdtMethodDef, g_cl_list[i], &hEnum))) + { + while(g_pImport->EnumNext(&hEnum, &tkMember)) + { + if (FAILED(g_pImport->GetNameOfMethodDef(tkMember, &pcMember)) || + FAILED(g_pImport->GetSigOfMethodDef(tkMember, &cComSig, &pComSig))) + { + sprintf_s(szString, SZSTRING_SIZE, "// ERROR in the method record %08X", tkMember); + printLine(g_pFile, szString); + continue; + } + qbMemberSig.Shrink(0); + pcSig = cComSig ? PrettyPrintSig(pComSig, cComSig, "", &qbMemberSig, g_pImport,NULL) : "NO SIGNATURE"; + PREFIX_ASSUME(ProperName((char*)pcMember) != 0); + sprintf_s(szString,SZSTRING_SIZE,"// %08X [MET] %s::%s : %s", tkMember,szFQN,ProperName((char*)pcMember),pcSig); + printLine(g_pFile,szString); + } + } + g_pImport->EnumClose(&hEnum); + if(SUCCEEDED(g_pImport->EnumInit(mdtFieldDef, g_cl_list[i], &hEnum))) + { + while(g_pImport->EnumNext(&hEnum, &tkMember)) + { + if (FAILED(g_pImport->GetNameOfFieldDef(tkMember, &pcMember)) || + FAILED(g_pImport->GetSigOfFieldDef(tkMember, &cComSig, &pComSig))) + { + sprintf_s(szString, SZSTRING_SIZE, "// ERROR in the field record %08X", tkMember); + printLine(g_pFile, szString); + continue; + } + qbMemberSig.Shrink(0); + pcSig = cComSig ? PrettyPrintSig(pComSig, cComSig, "", &qbMemberSig, g_pImport,NULL) : "NO SIGNATURE"; + PREFIX_ASSUME(ProperName((char*)pcMember) != 0); + sprintf_s(szString,SZSTRING_SIZE,"// %08X [FLD] %s::%s : %s", tkMember,szFQN,ProperName((char*)pcMember),pcSig); + printLine(g_pFile,szString); + } + } + g_pImport->EnumClose(&hEnum); + if(SUCCEEDED(g_pImport->EnumInit(mdtEvent, g_cl_list[i], &hEnum))) + { + while(g_pImport->EnumNext(&hEnum, &tkMember)) + { + if (FAILED(g_pImport->GetEventProps(tkMember,&pcMember,&dwAttrs,&tkEventType))) + { + sprintf_s(szString, SZSTRING_SIZE, "// Invalid Event %08X record", tkMember); + printLine(g_pFile, szString); + continue; + } + qbMemberSig.Shrink(0); + pcSig = "NO TYPE"; + if(RidFromToken(tkEventType)) + { + switch(TypeFromToken(tkEventType)) + { + case mdtTypeRef: + case mdtTypeDef: + case mdtTypeSpec: + pcSig = PrettyPrintClass(&qbMemberSig,tkEventType,g_pImport); + break; + default: + break; + } + } + PREFIX_ASSUME(ProperName((char*)pcMember) != 0); + sprintf_s(szString,SZSTRING_SIZE,"// %08X [EVT] %s::%s : %s", tkMember,szFQN,ProperName((char*)pcMember),pcSig); + printLine(g_pFile,szString); + } + } + g_pImport->EnumClose(&hEnum); + if(SUCCEEDED(g_pImport->EnumInit(mdtProperty, g_cl_list[i], &hEnum))) + { + while(g_pImport->EnumNext(&hEnum, &tkMember)) + { + if (FAILED(g_pImport->GetPropertyProps(tkMember,&pcMember,&dwAttrs,&pComSig,&cComSig))) + { + sprintf_s(szString, SZSTRING_SIZE, "// Invalid Property %08X record", tkMember); + printLine(g_pFile, szString); + continue; + } + qbMemberSig.Shrink(0); + pcSig = cComSig ? PrettyPrintSig(pComSig, cComSig, "", &qbMemberSig, g_pImport,NULL) : "NO SIGNATURE"; + PREFIX_ASSUME(ProperName((char*)pcMember) != 0); + sprintf_s(szString,SZSTRING_SIZE,"// %08X [PRO] %s::%s : %s", tkMember,szFQN,ProperName((char*)pcMember),pcSig); + printLine(g_pFile,szString); + } + } + g_pImport->EnumClose(&hEnum); + } + printLine(g_pFile,"//=============== END SUMMARY =================================="); +} +void DumpRTFPrefix(void* GUICookie,BOOL fFontDefault) +{ + g_fDumpRTF = FALSE; + printLine(GUICookie,"{\\rtf1\\ansi"); + if(fFontDefault) + printLine(GUICookie,"{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset1 Courier New;}{\\f1\\fswiss\\fcharset1 Arial;}}"); + printLine(GUICookie,"{\\colortbl ;\\red0\\green0\\blue128;\\red0\\green128\\blue0;\\red255\\green0\\blue0;}"); + printLine(GUICookie,"\\viewkind4\\uc1\\pard\\f0\\fs20"); + g_fDumpRTF = TRUE; +} +void DumpRTFPostfix(void* GUICookie) +{ + g_fDumpRTF = FALSE; + printLine(GUICookie,"}"); + g_fDumpRTF = TRUE; +} +mdToken ClassOf(mdToken tok) +{ + mdToken retval=0; + switch(TypeFromToken(tok)) + { + case mdtTypeDef: + case mdtTypeRef: + case mdtTypeSpec: + retval = tok; + break; + + case mdtFieldDef: + case mdtMethodDef: + case mdtMemberRef: + if (FAILED(g_pImport->GetParentToken(tok, &retval))) + { + retval = mdTokenNil; + } + else + { + retval = ClassOf(retval); + } + break; + + default: + break; + } + return retval; +} +void DumpRefs(BOOL fClassesOnly) +{ + CQuickBytes out; + DynamicArray<TokPair> *refs = g_refs; + TokPair *newrefs = NULL; + mdToken tkThisUser,tkThisRef; + mdToken tkLastUser = 0xFFFFFFFF, tkLastRef=0xFFFFFFFF; + DWORD i=0,j=0; + + g_refs = NULL; + printLine(g_pFile,COMMENT((char*)0)); + printLine(g_pFile,"//============ R E F E R E N C E S ==========================="); + strcpy_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH,"// "); + if(fClassesOnly && g_NumRefs) + { + if((newrefs = new TokPair[g_NumRefs])) + { + for(i=0; i<g_NumRefs; i++) + { + newrefs[i].tkUser = tkThisUser = ClassOf((*refs)[i].tkUser); + newrefs[i].tkRef = tkThisRef = ClassOf((*refs)[i].tkRef); + if(!tkThisUser) continue; + if(!tkThisRef) continue; + if(tkThisUser == tkThisRef) continue; + for(j = 0; j<i; j++) + { + if((newrefs[j].tkUser==tkThisUser)&&(newrefs[j].tkRef==tkThisRef)) + { + newrefs[i].tkRef = 0; + break; + } + } + } + } + else fClassesOnly = FALSE; + } + for(i = 0; i <g_NumRefs; i++) + { + if(fClassesOnly) + { + tkThisUser = newrefs[i].tkUser; + tkThisRef = newrefs[i].tkRef; + } + else + { + tkThisUser = (*refs)[i].tkUser; + tkThisRef = (*refs)[i].tkRef; + } + if(!tkThisUser) continue; + if(!tkThisRef) continue; + if(tkThisUser == tkThisRef) continue; + if((tkThisUser==tkLastUser)&&(tkThisRef==tkLastRef)) continue; + + strcpy_s(szString, SZSTRING_SIZE,g_szAsmCodeIndent); + if(tkThisUser != tkLastUser) + { + PrettyPrintToken(szString, tkThisUser, g_pImport,g_pFile,0); //TypeDef,TypeRef,TypeSpec,MethodDef,FieldDef,MemberRef,MethodSpec,String + strcat_s(szString, SZSTRING_SIZE, " references "); + printLine(g_pFile,szString); + tkLastUser = tkThisUser; + } + strcpy_s(szString, SZSTRING_SIZE,g_szAsmCodeIndent); + strcat_s(szString, SZSTRING_SIZE," - "); + PrettyPrintToken(szString, tkThisRef, g_pImport,g_pFile,0); //TypeDef,TypeRef,TypeSpec,MethodDef,FieldDef,MemberRef,MethodSpec,String + printLine(g_pFile,szString); + tkLastRef = tkThisRef; + + } + + printLine(g_pFile,"//=============== END REFERENCES ============================="); + printLine(g_pFile,COMMENT((char*)-1)); + g_refs = refs; + if(newrefs) VDELETE(newrefs); +} + +void CloseNamespace(__inout __nullterminated char* szString) +{ + if(strlen(g_szNamespace)) + { + char* szptr = &szString[0]; + if(g_szAsmCodeIndent[0]) g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%s ",g_szAsmCodeIndent, UNSCOPE()); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("// end of namespace %s"),ProperName(g_szNamespace)); + printLine(g_pFile,szString); + printLine(g_pFile,""); + g_szNamespace[0] = 0; + } +} + +FILE* OpenOutput(__in __nullterminated const WCHAR* wzFileName) +{ + FILE* pfile = NULL; + if(g_uCodePage == 0xFFFFFFFF) _wfopen_s(&pfile,wzFileName,L"wb"); + else _wfopen_s(&pfile,wzFileName,L"wt"); + + if(pfile) + { + if(g_uCodePage == CP_UTF8) fwrite("\357\273\277",3,1,pfile); + else if(g_uCodePage == 0xFFFFFFFF) fwrite("\377\376",2,1,pfile); + } + return pfile; +} + +FILE* OpenOutput(__in __nullterminated const char* szFileName) +{ + return OpenOutput(UtfToUnicode(szFileName)); +} + +// +// Init PELoader, dump file header info +// +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +BOOL DumpFile() +{ + BOOL fSuccess = FALSE; + static WCHAR wzInputFileName[MAX_FILENAME_LENGTH]; + static char szFilenameANSI[MAX_FILENAME_LENGTH*3]; + IMetaDataDispenser *pMetaDataDispenser = NULL; + const char *pszFilename = g_szInputFile; + + if(!(g_Mode & MODE_GUI)) + { + if(g_fDumpHTML) + { + printLine(g_pFile, "<HTML>"); + printLine(g_pFile, "<HEAD>"); + sprintf_s(szString,SZSTRING_SIZE,"<TITLE> %s - IL DASM</TITLE>",g_szInputFile); + printLine(g_pFile, szString); + printLine(g_pFile, "</HEAD>"); + printLine(g_pFile, "<BODY>"); + printLine(g_pFile, "<FONT SIZE=3 FACE=\"Arial\">"); + printLine(g_pFile, "<PRE>"); + } + else if(g_fDumpRTF) + { + DumpRTFPrefix(g_pFile,TRUE); + } + DumpPreamble(); + } + { + char* pch = strrchr(g_szInputFile,'.'); + if(pch && (!_stricmp(pch+1,"lib") || !_stricmp(pch+1,"obj"))) + { + if(!(g_Mode & MODE_GUI)) + DumpMetaInfo(g_wszFullInputFile,g_pszObjFileName,g_pFile); + return FALSE; + } + } + + if(g_pPELoader) goto DoneInitialization; // skip initialization, it's already done + + g_pPELoader = new PELoader(); + if (g_pPELoader == NULL) + { + printError(g_pFile,RstrUTF(IDS_E_INITLDR)); + goto exit; + } + + memset(wzInputFileName,0,sizeof(WCHAR)*MAX_FILENAME_LENGTH); + WszMultiByteToWideChar(CP_UTF8,0,pszFilename,-1,wzInputFileName,MAX_FILENAME_LENGTH); + memset(szFilenameANSI,0,MAX_FILENAME_LENGTH*3); + WszWideCharToMultiByte(g_uConsoleCP,0,wzInputFileName,-1,szFilenameANSI,MAX_FILENAME_LENGTH*3,NULL,NULL); + fSuccess = g_pPELoader->open(wzInputFileName); + + if (fSuccess == FALSE) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_FILEOPEN), pszFilename); + printError(g_pFile,szString); + SDELETE(g_pPELoader); + g_pPELoader = NULL; + goto exit; + } + fSuccess = FALSE; + + if (g_pPELoader->getCOMHeader(&g_CORHeader) == FALSE) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_NOCORHDR), pszFilename); + printError(g_pFile,szString); + if (g_fDumpHeader) + DumpHeader(g_CORHeader,g_pFile); + goto exit; + } + + if (VAL16(g_CORHeader->MajorRuntimeVersion) == 1 || VAL16(g_CORHeader->MajorRuntimeVersion) > COR_VERSION_MAJOR) + { + sprintf_s(szString,SZSTRING_SIZE,"CORHeader->MajorRuntimeVersion = %d",VAL16(g_CORHeader->MajorRuntimeVersion)); + printError(g_pFile,szString); + printError(g_pFile,RstrUTF(IDS_E_BADCORHDR)); + goto exit; + } + g_tkEntryPoint = VAL32(IMAGE_COR20_HEADER_FIELD(*g_CORHeader, EntryPointToken)); // integration with MetaInfo + + +#if defined(_DEBUG) && defined(FEATURE_PREJIT) + if (g_fNGenNativeMetadata) + { + //if this is an ngen image, use the native metadata. + if( !g_CORHeader->ManagedNativeHeader.Size ) + { + printError( g_pFile, "/native only works on NGen images." ); + goto exit; + } + CORCOMPILE_HEADER * pNativeHeader; + g_pPELoader->getVAforRVA(VAL32(g_CORHeader->ManagedNativeHeader.VirtualAddress), (void**)&pNativeHeader); + g_pPELoader->getVAforRVA(VAL32(pNativeHeader->ManifestMetaData.VirtualAddress), &g_pMetaData); + g_cbMetaData = VAL32(pNativeHeader->ManifestMetaData.Size); + } + else +#endif + { + if (g_pPELoader->getVAforRVA(VAL32(g_CORHeader->MetaData.VirtualAddress),&g_pMetaData) == FALSE) + { + printError(g_pFile, RstrUTF(IDS_E_OPENMD)); + if (g_fDumpHeader) + DumpHeader(g_CORHeader, g_pFile); + goto exit; + } + g_cbMetaData = VAL32(g_CORHeader->MetaData.Size); + } + + const DWORD openFlags = ofRead | (g_fProject ? 0 : ofNoTransform); + if (FAILED(g_pCLRRuntimeHostInternal->GetMetaDataInternalInterface( + (BYTE *)g_pMetaData, + g_cbMetaData, + openFlags, + IID_IMDInternalImport, + (LPVOID *)&g_pImport))) + { + if (g_fDumpHeader) + DumpHeader(g_CORHeader, g_pFile); + printError(g_pFile, RstrUTF(IDS_E_OPENMD)); + goto exit; + } + + TokenSigInit(g_pImport); + if (FAILED(CoCreateInstance(CLSID_CorMetaDataDispenser, 0, CLSCTX_INPROC_SERVER, IID_IMetaDataDispenser, (LPVOID*)&pMetaDataDispenser))) + { + if (g_fDumpHeader) + DumpHeader(g_CORHeader, g_pFile); + printError(g_pFile, RstrUTF(IDS_E_OPENMD)); + goto exit; + } + if (FAILED(pMetaDataDispenser->OpenScopeOnMemory(g_pMetaData, g_cbMetaData, openFlags, IID_IMetaDataImport2, (LPUNKNOWN *)&g_pPubImport ))) + { + if (g_fDumpHeader) + DumpHeader(g_CORHeader, g_pFile); + printError(g_pFile, RstrUTF(IDS_E_OPENMD)); + goto exit; + } + + + // Get a symbol binder. + ISymUnmanagedBinder *binder; + HRESULT hr; + + hr = CoCreateInstance(CLSID_CorSymBinder_SxS, NULL, + CLSCTX_INPROC_SERVER, + IID_ISymUnmanagedBinder, + (void**)&binder); + + if (SUCCEEDED(hr)) + { + hr = binder->GetReaderForFile(g_pPubImport, + wzInputFileName, + NULL, + &g_pSymReader); + + // Release the binder + binder->Release(); + } + + if (FAILED(hr)) + g_fShowSource = FALSE; + + if((g_uNCA = g_pImport->GetCountWithTokenKind(mdtCustomAttribute))) + { + g_rchCA = new char[g_uNCA+1]; + _ASSERTE(g_rchCA); + } + + EnumClasses(); + EnumTypedefs(); + +DoneInitialization: + if(g_uNCA) + { + _ASSERTE(g_rchCA); + memset(g_rchCA,0,g_uNCA+1); + } +#ifndef _DEBUG + if(HasSuppressingAttribute()) + { + if (g_fDumpHeader) + DumpHeader(g_CORHeader,g_pFile); + if(g_fDumpMetaInfo) + DumpMetaInfo(g_wszFullInputFile,NULL,g_pFile); + printError(g_pFile,RstrUTF(IDS_E_SUPPRESSED)); + goto CloseFileAndExit; + } +#endif + + if (g_Mode & MODE_GUI) + { + GUIAddItemsToList(); + } + else + { + // Dump the CLR header info if requested. + printLine(g_pFile,COMMENT((char*)0)); // start multiline comment + if (g_fDumpHeader) + { + DumpHeader(g_CORHeader,g_pFile); + DumpHeaderDetails(g_CORHeader,g_pFile); + } + else + DumpVTables(g_CORHeader,g_pFile); + if (g_fDumpStats) + DumpStatistics(g_CORHeader,g_pFile); + + if(g_fDumpClassList) PrintClassList(); + // MetaInfo integration: + if(g_fDumpMetaInfo) DumpMetaInfo(g_wszFullInputFile,NULL,g_pFile); + + if(g_fDumpSummary) DumpSummary(); + printLine(g_pFile,COMMENT((char*)-1)); // end multiline comment + + if(g_fShowRefs) g_refs = new DynamicArray<TokPair>; + + if (g_fDumpAsmCode) + { + g_szNamespace[0] = 0; + if(g_tkClassToDump) //g_tkClassToDump is set in EnumClasses + { + DumpClass(TopEncloser(g_tkClassToDump), VAL32(IMAGE_COR20_HEADER_FIELD(*g_CORHeader, EntryPointToken)),g_pFile,7); //7-dump everything at once + CloseNamespace(szString); + goto ReportAndExit; + } + { + HENUMInternal hEnumMethod; + ULONG ulNumGlobalFunc=0; + if (SUCCEEDED(g_pImport->EnumGlobalFunctionsInit(&hEnumMethod))) + { + ulNumGlobalFunc = g_pImport->EnumGetCount(&hEnumMethod); + g_pImport->EnumClose(&hEnumMethod); + } + if(g_fShowProgressBar) + CreateProgressBar((LONG) (g_NumClasses + ulNumGlobalFunc)); + } + ProgressStep(); + g_fAbortDisassembly = FALSE; + //DumpVtable(g_pFile); + DumpMscorlib(g_pFile); + if(g_fDumpTypeList) DumpTypelist(g_pFile); + DumpManifest(g_pFile); + DumpTypedefs(g_pFile); + /* First dump the classes w/o members*/ + if(g_fForwardDecl && g_NumClasses) + { + printLine(g_pFile,COMMENT("//")); + printLine(g_pFile,COMMENT("// ============== CLASS STRUCTURE DECLARATION ==================")); + printLine(g_pFile,COMMENT("//")); + for (DWORD i = 0; i < g_NumClasses; i++) + { + if(g_cl_enclosing[i] == mdTypeDefNil) // nested classes are dumped within enclosing ones + { + DumpClass(g_cl_list[i], VAL32(IMAGE_COR20_HEADER_FIELD(*g_CORHeader, EntryPointToken)),g_pFile,2); // 2=header+nested classes + } + } + CloseNamespace(szString); + printLine(g_pFile,""); + printLine(g_pFile,COMMENT("// =============================================================")); + printLine(g_pFile,""); + } + /* Second, dump the global fields and methods */ + DumpGlobalFields(); + DumpGlobalMethods(VAL32(IMAGE_COR20_HEADER_FIELD(*g_CORHeader, EntryPointToken))); + /* Third, dump the classes with members */ + if(g_NumClasses) + { + printLine(g_pFile,""); + printLine(g_pFile,COMMENT("// =============== CLASS MEMBERS DECLARATION ===================")); + if(g_fForwardDecl) + { + printLine(g_pFile,COMMENT("// note that class flags, 'extends' and 'implements' clauses")); + printLine(g_pFile,COMMENT("// are provided here for information only")); + } + printLine(g_pFile,""); + for (DWORD i = 0; i < g_NumClasses; i++) + { + if(g_cl_enclosing[i] == mdTypeDefNil) // nested classes are dumped within enclosing ones + { + DumpClass(g_cl_list[i], VAL32(IMAGE_COR20_HEADER_FIELD(*g_CORHeader, EntryPointToken)),g_pFile,7); //7=everything + if(g_fAbortDisassembly) + { + printError(g_pFile,""); + printError(g_pFile,RstrUTF(IDS_E_DASMABORT)); + fSuccess = FALSE; + goto CloseFileAndExit; + } + } + } + CloseNamespace(szString); + printLine(g_pFile,""); + printLine(g_pFile,COMMENT("// =============================================================")); + printLine(g_pFile,""); + } + if(g_fShowCA) + { + if(g_uNCA) _ASSERTE(g_rchCA); + for(DWORD i=1; i<= g_uNCA; i++) + { + if(g_rchCA[i] == 0) DumpCustomAttribute(TokenFromRid(i,mdtCustomAttribute),g_pFile,true); + } + } + if(g_fAbortDisassembly) + { + printError(g_pFile,""); + printError(g_pFile,RstrUTF(IDS_E_DASMABORT)); + fSuccess = FALSE; + goto CloseFileAndExit; + } + ProgressStep(); + +#if (0) + /* Third, dump GC/EH info about the native methods, using the IPMap */ + IMAGE_DATA_DIRECTORY *pIPMap; + if (g_pPELoader->IsPE32()) + { + pIPMap = &g_pPELoader->ntHeaders32()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; + } + else + { + pIPMap = &g_pPELoader->ntHeaders64()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; + } + DWORD IPMapSize; + const BYTE * ipmap; + IPMapSize = VAL32(pIPMap->Size); + g_pPELoader->getVAforRVA(VAL32(pIPMap->VirtualAddress), (void **) &ipmap); + + DumpNativeInfo(ipmap, IPMapSize); +#endif + + // If there were "ldptr", dump the .rdata section with labels + if(g_iPtrCount) + { + //first, sort the pointers + int i,j; + bool swapped; + do { + swapped = FALSE; + + for(i = 1; i < g_iPtrCount; i++) + { + if((*g_pPtrTags)[i-1] > (*g_pPtrTags)[i]) + { + j = (*g_pPtrTags)[i-1]; + (*g_pPtrTags)[i-1] = (*g_pPtrTags)[i]; + (*g_pPtrTags)[i] = j; + j = (*g_pPtrSize)[i-1]; + (*g_pPtrSize)[i-1] = (*g_pPtrSize)[i]; + (*g_pPtrSize)[i] = j; + swapped = TRUE; + } + } + } while(swapped); + + //second, dump data for each ptr as binarray + + IMAGE_SECTION_HEADER *pSecHdr = NULL; + if(g_pPELoader->IsPE32()) + pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders32()); + else + pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders64()); + + DWORD dwNumberOfSections; + if(g_pPELoader->IsPE32()) + dwNumberOfSections = VAL16(g_pPELoader->ntHeaders32()->FileHeader.NumberOfSections); + else + dwNumberOfSections = VAL16(g_pPELoader->ntHeaders64()->FileHeader.NumberOfSections); + + DWORD fromPtr,toPtr,limPtr; + char* szptr; + for(j = 0; j < g_iPtrCount; j++) + { + BYTE *pb; + + fromPtr = (*g_pPtrTags)[j]; + for (i=0; i < (int)dwNumberOfSections; i++,pSecHdr++) + { + if((fromPtr >= VAL32(pSecHdr->VirtualAddress))&& + (fromPtr < VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize))) break; + } + if(i == (int)dwNumberOfSections) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_ROGUEPTR), fromPtr); + printLine(g_pFile,szString); + break; + } + // OK, now we have the section; what about end of BLOB? + const char* szTls = "D_"; + if(strcmp((char*)(pSecHdr->Name),".tls")==0) szTls = "T_"; + else if(strcmp((char*)(pSecHdr->Name),".text")==0) szTls = "I_"; + if(j == g_iPtrCount-1) + { + toPtr = VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize); + } + else + { + toPtr = (*g_pPtrTags)[j+1]; + if(toPtr > VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize)) + { + toPtr = VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize); + } + } + if(toPtr - fromPtr > (*g_pPtrSize)[j]) toPtr = fromPtr + (*g_pPtrSize)[j]; + limPtr = toPtr; // at limPtr and after, pad with 0 + if(limPtr > VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->SizeOfRawData)) + limPtr = VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->SizeOfRawData); + PrintBlob: + szptr = szString; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".data")); + if(*szTls=='T') szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("tls ")); + else if(*szTls=='I') szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("cil ")); + if(fromPtr >= limPtr) + { // uninitialized data + sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%8.8X = %s[%d]",szTls,fromPtr,KEYWORD("int8"),toPtr-fromPtr); + printLine(g_pFile,szString); + } + else + { // initialized data + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%8.8X = %s (",szTls,fromPtr,KEYWORD("bytearray")); + printLine(g_pFile,szString); + sprintf_s(szString,SZSTRING_REMAINING_SIZE(szptr),"%s ",g_szAsmCodeIndent); + pb = g_pPELoader->base() + + VAL32(pSecHdr->PointerToRawData) + + fromPtr - VAL32(pSecHdr->VirtualAddress); + // now fromPtr is the beginning of the BLOB, and toPtr is [exclusive] end of it + DumpHexbytes(szString, pb, fromPtr, toPtr, limPtr); + } + // to preserve alignment, dump filler if any + if(limPtr == toPtr) // don't need filler if it's the last item in section + { + if((j < g_iPtrCount-1)&&(toPtr < (DWORD)((*g_pPtrTags)[j+1]))) + { + DWORD align; + DWORD stptr = (DWORD)(*g_pPtrTags)[j+1]; + for(align = 1; (align & stptr)==0; align = align << 1); + align -= 1; + if(toPtr & align) + { + fromPtr = toPtr; + toPtr = (toPtr + align)&~align; + goto PrintBlob; + } + } + } + } + } +ReportAndExit: + printLine(g_pFile,COMMENT(RstrUTF(IDS_E_DASMOK))); + fSuccess = TRUE; + } + fSuccess = TRUE; + if(g_pFile) // dump .RES file (if any), if not to console + { + WCHAR wzResFileName[2048], *pwc; + memset(wzResFileName,0,sizeof(wzResFileName)); + WszMultiByteToWideChar(CP_UTF8,0,g_szOutputFile,-1,wzResFileName,2048); + pwc = wcsrchr(wzResFileName,L'.'); + if(pwc == NULL) pwc = &wzResFileName[wcslen(wzResFileName)]; + wcscpy_s(pwc, 2048 - (pwc - wzResFileName), L".res"); + DWORD ret = DumpResourceToFile(wzResFileName); + switch(ret) + { + case 0: szString[0] = 0; break; + case 1: sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_W_CREATEDW32RES)/*"// WARNING: Created Win32 resource file %ls"*/, + UnicodeToUtf(wzResFileName)); break; + case 0xDFFFFFFF: sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_CORRUPTW32RES)/*"// ERROR: Corrupt Win32 resources"*/); break; + case 0xEFFFFFFF: sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_CANTOPENW32RES)/*"// ERROR: Unable to open file %ls"*/, + UnicodeToUtf(wzResFileName)); break; + case 0xFFFFFFFF: sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_CANTACCESSW32RES)/*"// ERROR: Unable to access Win32 resources"*/); break; + } + if(szString[0]) + { + if(ret == 1) printLine(g_pFile,COMMENT(szString)); + else printError(g_pFile,szString); + } + } + if(g_fShowRefs) DumpRefs(TRUE); + if(g_fDumpHTML) + { + printLine(g_pFile, "</PRE>"); + printLine(g_pFile, "</BODY>"); + printLine(g_pFile, "</HTML>"); + } + else if(g_fDumpRTF) + { + DumpRTFPostfix(g_pFile); + } + +CloseFileAndExit: + if(g_pFile) + { + fclose(g_pFile); + g_pFile = NULL; + } + DestroyProgressBar(); + } + +exit: + if (pMetaDataDispenser) + pMetaDataDispenser->Release(); + return fSuccess; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +#ifdef _MSC_VER +#pragma warning(default : 4640) +#endif + + diff --git a/src/ildasm/dasm.rc b/src/ildasm/dasm.rc new file mode 100644 index 0000000000..a1619cff90 --- /dev/null +++ b/src/ildasm/dasm.rc @@ -0,0 +1,503 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "resource.h" + +#ifndef FEATURE_PAL +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include <winresrc.h> + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS +#endif // !FEATURE_PAL + +#define FX_VER_FILEDESCRIPTION_STR "Microsoft .NET Framework IL disassembler\0" + +#include <fxver.h> +#include <fxver.rc> + +#include <copyrightstring.rc> + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef FEATURE_PAL + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON2 ICON DISCARDABLE "Litening.ico" + +#if FX_VFT == VFT_DLL + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_FIELD BITMAP MOVEABLE PURE "field.bmp" +IDB_METHOD BITMAP MOVEABLE PURE "method.bmp" +IDB_STATICFIELD BITMAP MOVEABLE PURE "staticfield.bmp" +IDB_STATICMETHOD BITMAP MOVEABLE PURE "staticmethod.bmp" +IDB_REDARROW BITMAP MOVEABLE PURE "redarrow.bmp" +IDB_EVENT BITMAP DISCARDABLE "event.bmp" +IDB_PROP BITMAP DISCARDABLE "prop.bmp" +IDB_NAMESPACE BITMAP DISCARDABLE "namespace.bmp" +IDB_CLASS BITMAP DISCARDABLE "classa.bmp" +IDB_CLASSENUM BITMAP DISCARDABLE "classe.bmp" +IDB_CLASSINT BITMAP DISCARDABLE "classi.bmp" +IDB_CLASSVAL BITMAP DISCARDABLE "classv.bmp" + +IDB_METHOD_GEN BITMAP MOVEABLE PURE "methodg.bmp" +IDB_STATICMETHOD_GEN BITMAP MOVEABLE PURE "staticmethodg.bmp" +IDB_CLASS_GEN BITMAP DISCARDABLE "classag.bmp" +IDB_CLASSENUM_GEN BITMAP DISCARDABLE "classeg.bmp" +IDB_CLASSINT_GEN BITMAP DISCARDABLE "classig.bmp" +IDB_CLASSVAL_GEN BITMAP DISCARDABLE "classvg.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 157, 306 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Dump options" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON L"OK",IDOK,13,285,50,14 + PUSHBUTTON L"Cancel",IDCANCEL,81,285,50,14 + GROUPBOX L"Encoding",IDC_STATIC,13,3,129,28 + CONTROL L"ANSI",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,19,16,34,9 + CONTROL L"UTF-8",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,55,16,34, + 9 + CONTROL L"Unicode",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,91,16, + 40,9 + CONTROL L"Dump Class List",IDC_CHECK19,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,36,106,10 + CONTROL L"Dump Statistics",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,48,106,10 + CONTROL L"Show Progress Bar",IDC_CHECK18,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,60,124,11 + CONTROL L"Dump Header",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,73,106,10 + CONTROL L"Dump IL Code",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,86,106,10 + CONTROL L"Token Values",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,99,106,10 + CONTROL L"Actual Bytes",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,110,106,10 + CONTROL L"Line Numbers",IDC_CHECK20,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,120,106,10 + CONTROL L"Source Lines",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,131,106,10 + CONTROL L"Expand try/catch",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,142,106,10 + CONTROL L"Dump Metainfo",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,158,106,10 + CONTROL L"More HEX",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,174,106,10 + CONTROL L"Raw: Counts,Sizes",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,185,106,10 + CONTROL L"Raw: Header",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,198,106,10 + CONTROL L"Raw: Header,Schema",IDC_CHECK14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 37,209,106,10 + CONTROL L"Raw: Header,Schema,Rows",IDC_CHECK15,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,37,222,106,10 + CONTROL L"Raw: Heaps",IDC_CHECK17,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,233,106,10 + CONTROL L"Unresolved Externals",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 37,246,106,10 + CONTROL L"Validate",IDC_CHECK16,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,257,106,10 + CONTROL L"Debug",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 37,270,106,10 +END + +IDD_ABOUT DIALOGEX 0, 0, 289, 112 +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION +EXSTYLE WS_EX_CLIENTEDGE +CAPTION L"About IL DASM" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON L"OK",ID_ABOUT_OK,122,83,50,14 + ICON IDI_ICON2,IDC_STATIC,18,22,21,20,0 + LTEXT L"Static",IDC_ABOUT_LINE1,47,22,279,11 + LTEXT L"Static",IDC_ABOUT_LINE2,47,38,279,11 + LTEXT L"Static",IDC_ABOUT_LINE3,47,56,279,11 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +FileAccel ACCELERATORS MOVEABLE PURE +BEGIN + "O", 1, VIRTKEY, CONTROL + "D", 2, VIRTKEY, CONTROL + "T", 3, VIRTKEY, CONTROL + "X", 4, VIRTKEY, CONTROL + "M", 21, VIRTKEY, CONTROL + VK_F1, 31, VIRTKEY + VK_ESCAPE, 4, VIRTKEY +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 150 + TOPMARGIN, 3 + BOTTOMMARGIN, 299 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 232 + TOPMARGIN, 7 + BOTTOMMARGIN, 105 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_FILE L"&File" + IDS_VIEW L"&View" + IDS_HELP L"&Help" + IDS_OPEN L"&Open\tCtrl+O" + IDS_DUMP L"&Dump\tCtrl+D" + IDS_DUMPTREE L"Dump &TreeView\tCtrl+T" + IDS_EXIT L"E&xit\tCtrl+X" + IDS_FONTS L"Set &Fonts" + IDS_FONT_TREE L"&Tree view" + IDS_FONT_DASM L"&Disassembly" + IDS_SORT_BY_NAME L"Sort by &name" + IDS_SHOW_PUB L"Hide &Public" + IDS_SHOW_PRIV L"Hide P&rivate" + IDS_SHOW_FAM L"Hide Famil&y" + IDS_SHOW_ASM L"Hide &Assembly" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_FIND L"&Find" + IDS_FINDNEXT L"Find &Next" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MI_DEBUG L"&Debug" + IDS_MI_SCHEMA L"Raw:Header,Sch&ema" + IDS_MI_RAW L"Raw:Header,Schema,&Rows" + IDS_MI_HEAPS L"Raw:Hea&ps" + IDS_MI_VALIDATE L"&Validate" + IDS_SHOW_METAINFO L"&Show!\tCtrl+M" + IDS_ABOUT L"&About IL DASM" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_SHOW_FAA L"Hide FamAN&DAssem" + IDS_SHOW_FOA L"Hide Fam&ORAssem" + IDS_SHOW_PSCOPE L"Hide Private&Scope" + IDS_FULL_INFO L"Show member &types" + IDS_BYTES L"Show &bytes" + IDS_TOKENS L"Show token &values" + IDS_SOURCELINES L"Show source &lines" + IDS_QUOTEALLNAMES L"&Quote all names" + IDS_EXPANDTRY L"E&xpand try/catch" + IDS_SHOW_HEADER L"&Headers" + IDS_SHOW_STAT L"Stat&istics" + IDS_METAINFO L"&MetaInfo" + IDS_MI_HEADER L"Raw:&Header" + IDS_MI_HEX L"&More HEX" + IDS_MI_CSV L"Raw:&Counts,Sizes" + IDS_MI_UNREX L"&Unresolved ext." + IDS_TREEVIEWFCN L"Full &Class Names" + IDS_CAVERBAL L"V&erbal CA blobs" + IDS_DUMPRTF L"&Use RTF" +END + +#endif // FX_VFT == VFT_DLL +#endif // !FEATURE_PAL + +#if FX_VFT == VFT_DLL +STRINGTABLE DISCARDABLE +BEGIN + IDS_USAGE_TITLE L"ILDASM command line syntax" + IDS_USAGE_01 L"Usage: ildasm [options] <file_name> [options]\n\n" + IDS_USAGE_02 L"Options for output redirection:\n" +#ifndef FEATURE_PAL + IDS_USAGE_03 L" /OUT=<file name> Direct output to file rather than to GUI.\n" + IDS_USAGE_04 L" /TEXT Direct output to console window rather than to GUI.\n\n" + IDS_USAGE_04A L" /HTML Output in HTML format (valid with /OUT option only).\n" + IDS_USAGE_04B L" /RTF Output in rich text format (invalid with /TEXT option).\n" + IDS_USAGE_05 L"Options for GUI or file/console output (EXE and DLL files only):\n" +#else + IDS_USAGE_03 L" /OUT=<file name> Direct output to file rather than to console.\n" + IDS_USAGE_04A L" /HTML Output in HTML format (valid with /OUT option only).\n" + IDS_USAGE_04B L" /RTF Output in rich text format (valid with /OUT option only).\n" + IDS_USAGE_05 L"Options for file/console output:\n" +#endif +#ifdef OWNER_OPTION_ENABLED + IDS_USAGE_06 L" /OWNER=<owner name> Set owner name to disassemble a protected PE file.\n" +#endif + IDS_USAGE_07 L" /BYTES Show actual bytes (in hex) as instruction comments.\n" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_USAGE_08 L" /RAWEH Show exception handling clauses in raw form.\n" + IDS_USAGE_09 L" /TOKENS Show metadata tokens of classes and members.\n" + IDS_USAGE_10 L" /SOURCE Show original source lines as comments.\n" +#ifdef _DEBUG + IDS_USAGE_10A L" /PRETTY This option is obsolete and no longer supported.\n" +#endif + IDS_USAGE_11 L" /LINENUM Include references to original source lines.\n" + IDS_USAGE_12 L" /VISIBILITY=<vis>[+<vis>...] Only disassemble the items with specified\n" + IDS_USAGE_13 L" visibility. (<vis> = PUB | PRI | FAM | ASM | FAA | FOA | PSC)\n" + IDS_USAGE_14 L" /PUBONLY Only disassemble the public items (same as /VIS=PUB).\n" + IDS_USAGE_15 L" /QUOTEALLNAMES Include all names into single quotes.\n" + IDS_USAGE_15A L" /NOCA Suppress output of custom attributes.\n" + IDS_USAGE_15B L" /CAVERBAL Output CA blobs in verbal form (default - in binary form).\n" +#ifndef FEATURE_PAL + IDS_USAGE_16 L" /NOBAR Suppress disassembly progress bar window pop-up.\n\n" + IDS_USAGE_17 L"The following options are valid for file/console output only:\n" + IDS_USAGE_18 L"Options for EXE and DLL files:\n" +#endif + IDS_USAGE_19 L" /UTF8 Use UTF-8 encoding for output (default - ANSI).\n" + IDS_USAGE_20 L" /UNICODE Use UNICODE encoding for output.\n" + IDS_USAGE_21 L" /NOIL Suppress IL assembler code output.\n" + IDS_USAGE_21A L" /FORWARD Use forward class declaration.\n" + IDS_USAGE_21B L" /TYPELIST Output full list of types (to preserve type ordering in round-trip).\n" + IDS_USAGE_21C L" /PROJECT Display .NET projection view if input is a .winmd file.\n" + IDS_USAGE_22 L" /HEADERS Include file headers information in the output.\n" + IDS_USAGE_23 L" /ITEM=<class>[::<method>[(<sig>)] Disassemble the specified item only\n\n" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_USAGE_24 L" /STATS Include statistics on the image.\n" + IDS_USAGE_25 L" /CLASSLIST Include list of classes defined in the module.\n" + IDS_USAGE_26 L" /ALL Combination of /HEADER,/BYTES,/STATS,/CLASSLIST,/TOKENS\n\n" +#ifndef FEATURE_PAL + IDS_USAGE_27 L"Options for EXE,DLL,OBJ and LIB files:\n" +#endif + IDS_USAGE_28 L" /METADATA[=<specifier>] Show MetaData, where <specifier> is:\n" + IDS_USAGE_29 L" MDHEADER Show MetaData header information and sizes.\n" + IDS_USAGE_30 L" HEX Show more things in hex as well as words.\n" + IDS_USAGE_31 L" CSV Show the record counts and heap sizes.\n" + IDS_USAGE_32 L" UNREX Show unresolved externals.\n" +#ifndef FEATURE_PAL + IDS_USAGE_33 L" DEBUG Show debug information in addition to other MetaData.\n" +#endif + IDS_USAGE_34 L" SCHEMA Show the MetaData header and schema information.\n" + IDS_USAGE_35 L" RAW Show the raw MetaData tables.\n" + IDS_USAGE_36 L" HEAPS Show the raw heaps.\n" + IDS_USAGE_37 L" VALIDATE Validate the consistency of the metadata.\n" +#ifndef FEATURE_PAL + IDS_USAGE_38 L"Options for LIB files only:\n" + IDS_USAGE_39 L" /OBJECTFILE=<obj_file_name> Show MetaData of a single object file in library\n" +#endif +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_USAGE_40 L" /ALL Combination of /HEADER, /BYTES, /TOKENS\n\n" + IDS_USAGE_41 L"\nOption key is '-' or '/', options are recognized by first 3 characters\n\n" + IDS_USAGE_42 L"Example: ildasm /tok /byt myfile.exe /out=myfile.il\n\n" + IDS_USAGE_43 L"\n\nPress any key to close the console window..." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_E_INITLDR L"error : PELoader initialization failed" + IDS_E_FILEOPEN L"error : File '%s' not found or not a PE file" + IDS_E_NOCORHDR L"error : '%s' has no valid CLR header and cannot be disassembled" + IDS_E_BADCORHDR L"error : Bad CLR header, or the version of the file format is not supported" + IDS_E_OPENMD L"error : Failed to open meta data" + IDS_E_COPYRIGHT L"error : Copyrighted material - can not disassemble!" + IDS_E_DASMABORT L"********* DISASSEMBLY ABORTED BY THE OPERATOR **************" + IDS_E_DASMOK L"*********** DISASSEMBLY COMPLETE ***********************" + IDS_E_PARTDASM L"warning : THIS IS A PARTIAL DISASSEMBLY, NOT SUITABLE FOR RE-ASSEMBLING" + IDS_E_INSTRDT L"error : Failed to create instruction decoding table" + IDS_E_NOCOMPR L"error : Compression not supported" + IDS_E_CLSENUM L"error : Unable to enumerate classes" + IDS_E_SELFNSTD L"error : class %08X is nested in itself" + IDS_E_NOENCLOS L"error : class %08X is nested in missing class %08x" + IDS_E_INVALIDTK L"error : invalid token (%08x)" + IDS_E_INVALIDRECORD L"error : Invalid record (%08x)" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_E_UNEXPTYPE L"error : unexpected token type, expected %02x, got %02x" + IDS_E_AUTOCA L"--- The following custom attribute is added automatically, do not uncomment -------" + IDS_E_PARAMSEQNO L"error : parameter %d has sequence number %d (0x%X), parameter info skipped" + IDS_E_METHBEG L"Method begins at RVA 0x%x" + IDS_E_DASMERR L"%s ********* ERROR DISASSEMBLING THE METHOD IL CODE ***********" + IDS_E_DASMNATIVE L"Disassembly of native methods is not supported." + IDS_E_METHODRT L"Method provided by Runtime" + IDS_E_NORVA L"COULD NOT GET RVA" + IDS_E_MEMBRENUM L"Unable to enum members" + IDS_E_ODDMEMBER L"Unidentified member 0x%08X of class '%s'" + IDS_E_ENUMINIT L"*** EnumInit(mdtInterfaceImpl) failed" + IDS_E_NODATA L"No data." + IDS_E_VTFUTABLE L"Failed to get vtable fix-up table." + IDS_E_BOGUSRVA L"Bogus RVA for entry." + IDS_E_EATJTABLE L"Failed to get export address table jumps table." + IDS_E_EATJSIZE L"Error! size of ExportAddressTableJumps %d not a multiple of reserved size %d" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_E_RESFLAGS L"Error! reserved flags need to be 0." + IDS_E_MIHENTRY L"Failed to get vtable method data." + IDS_E_CODEMGRTBL L"Failed to get Code Manager table." + IDS_E_IMPORTDATA L"Failed to read import data." + IDS_E_COMIMAGE L"Not a CLR image" + IDS_E_MDDETAILS L"Unable to get MetaData details." + IDS_E_MISTART L"================================= M E T A I N F O ================================================\n" + IDS_E_MIEND L"================================= END OF METAINFO ================================================\n" + IDS_E_ONLYITEMS L"Only shown items having accessibility:" + IDS_E_ROGUEPTR L"ERROR: One of used pointers references undefined data (D_%8.8X)" + IDS_E_DECOMPRESS L"Failed to decompress method" + IDS_E_COMPRESSED L"Method is compressed" + IDS_E_CODESIZE L"Code size %d (0x%x)" + IDS_E_BOGUSLVSIG L"******** ERROR: Bogus local variable signature (0x%08X) ***********" + IDS_E_INSTRDECOD L"***Instruction decoding ERROR: %02X at position 0x%X (%d)" + IDS_E_INSTRTYPE L"ERROR: Unknown type 0x%X of instruction 0x%X" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_E_ARGINDEX L"%-10s %d // ERROR: invalid arg index (>=%d)" + IDS_E_LVINDEX L"%-10s %d // ERROR: invalid local var index (>=%d)" + IDS_E_SECTHEADER L"Error: no section header for RVA 0x%x, defaulting to empty string" + IDS_E_BADTOKENTYPE L"%-10s 0x%8.8X // ERROR: invalid token type" + IDS_E_MDAIMPORT L"ERROR: failed to obtain IMetaDataAssemblyImport (0x%08X)" + IDS_E_MDAFROMMDI L"ERROR: failed to obtain IMetaDataAssemblyImport from IMDInternalImport (0x%08X)" + IDS_E_MDIIMPORT L"ERROR: failed to obtain IMDInternalImport (0x%08X)" + IDS_E_NOMANIFEST L"Module contains no Manifest data" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_E_MULTIPLEINPUT L"MULTIPLE INPUT FILES SPECIFIED\n\n" + IDS_E_INVALIDOPTION L"INVALID COMMAND LINE OPTION: %s\n\n" + IDS_PROGRESSBOX L"ProgressBox" + IDS_DISASSEMBLING L"Disassembling" + IDS_PB_FILE L"File %s" + IDS_PB_FILE1 L"File ...%s" + IDS_PB_TOFILE L"To file %s" + IDS_PB_TOFILE1 L"To file ...%s" + IDS_PB_CLASSESDONE L"%d classes, %d done" + IDS_PB_GLOBALSDONE L"%d global methods, %d done" + IDS_PB_CANCEL L"Cancel" + IDS_PB_WRITINGDATA L"Writing global data" + IDS_W_CREATEDW32RES L"WARNING: Created Win32 resource file %s" + IDS_E_CORRUPTW32RES L"ERROR: Corrupt Win32 resources" + IDS_E_CANTOPENW32RES L"ERROR: Unable to open file %s" + IDS_E_CANTACCESSW32RES L"ERROR: Unable to access Win32 resources" + IDS_CANTVIEW_TX L"Can't view %s::%s(%s)" + IDS_CANTVIEW_HD L"Can't View IL" + IDS_ONLYPEINGUI L"ILDASM supports only PE files in graphic mode" + IDS_BADFILETYPE L"Invalid File Type" + IDS_E_CANTOPENOUT L"Unable to open '%s' for output." + IDS_E_CANTCREATEPROC L"Failed to CreateProcess\n\n" + IDS_TEXTTOOLARGEFORGUI L"Text too large for GUI. Use File/Dump menu entry to disassemble to file." + IDS_FILTER_IN L"PE file (*.exe,*.dll,*.mod,*.mdl,*.winmd)\t*.exe;*.dll;*.mod;*.mdl;*.winmd\tAny type (*.*)\t*.*\t\0" + IDS_FILTER_OUT L"IL file (*.il)\t*.il\tText file (*.txt) \t*.txt\tAny type (*.*)\t*.*\t\0" + IDS_FILTER_OUT2 L"Text file (*.txt) \t*.txt\tAny type (*.*)\t*.*\t\0" + IDS_CANNOTOPENFILE L"Cannot open file" + IDS_UNABLETOREGLIBS L"Unable to register libraries!" + IDS_ERRORREOPENINGFILE L"Error reopening the file with FileToken 0x%08X" + IDS_ASSEMNAMETOOLONG L"error *** Assembly name too long, truncated to 1023 characters" + IDS_ASMREFNAMETOOLONG L"error *** AssemblyRef name too long, truncated to 1023 characters" + IDS_ERRORCAPTION L"ERROR" + IDS_ILDASM_TITLE L"Microsoft (R) .NET Framework IL Disassembler" + IDS_VERSION L"Version %s" + IDS_W_CREATEDMRES L"WARNING: managed resource file %s created" + IDS_E_READINGMRES L"ERROR: reading managed resource %s at offset 0x%X" + IDS_RTL L"RTL_False" // change this to RTL_True on Arabic/Hebrew system + IDS_E_SUPPRESSED L"Protected module -- cannot disassemble" + IDS_LEGALCOPYRIGHT L"\251 Microsoft Corporation. All rights reserved." +END +#endif // FX_VFT == VFT_DLL + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + +#ifndef FEATURE_PAL + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + +#endif // !FEATURE_PAL diff --git a/src/ildasm/dasm_formattype.cpp b/src/ildasm/dasm_formattype.cpp new file mode 100644 index 0000000000..b196483fb8 --- /dev/null +++ b/src/ildasm/dasm_formattype.cpp @@ -0,0 +1,305 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +/******************************************************************************/ +/* dasm_formatType.cpp */ +/******************************************************************************/ +#include "ildasmpch.h" + +#include "formattype.h" + +BOOL g_fQuoteAllNames = FALSE; // used by ILDASM +BOOL g_fDumpTokens = FALSE; // used by ILDASM +LPCSTR *rAsmRefName = NULL; // used by ILDASM +ULONG ulNumAsmRefs = 0; // used by ILDASM +BOOL g_fDumpRTF = FALSE; // used by ILDASM +BOOL g_fDumpHTML = FALSE; // used by ILDASM +BOOL g_fUseProperName = FALSE; // used by ILDASM +DynamicArray<mdToken> *g_dups = NULL; // used by ILDASM +DWORD g_NumDups=0; // used by ILDASM +DynamicArray<TypeDefDescr> *g_typedefs = NULL; // used by ILDASM +DWORD g_NumTypedefs=0; // used by ILDASM + +// buffers created in Init and deleted in Uninit (dasm.cpp) +CQuickBytes * g_szBuf_KEYWORD = NULL; +CQuickBytes * g_szBuf_COMMENT = NULL; +CQuickBytes * g_szBuf_ERRORMSG = NULL; +CQuickBytes * g_szBuf_ANCHORPT = NULL; +CQuickBytes * g_szBuf_JUMPPT = NULL; +CQuickBytes * g_szBuf_UnquotedProperName = NULL; +CQuickBytes * g_szBuf_ProperName = NULL; + +// Protection against null names, used by ILDASM +const char * const szStdNamePrefix[] = {"MO","TR","TD","","FD","","MD","","PA","II","MR","","CA","","PE","","","SG","","","EV", +"","","PR","","","MOR","TS","","","","","AS","","","AR","","","FL","ET","MAR"}; + +//------------------------------------------------------------------------------- +// Reference analysis (ILDASM) +DynamicArray<TokPair> *g_refs = NULL; +DWORD g_NumRefs=0; +mdToken g_tkRefUser=0; // for PrettyPrintSig + +mdToken g_tkVarOwner = 0; +mdToken g_tkMVarOwner = 0; + +// Include the shared formatting routines +#include "formattype.cpp" + +// Special dumping routines for keywords, comments and errors, used by ILDASM + +const char* KEYWORD(__in_opt __nullterminated const char* szOrig) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + const char* szPrefix = ""; + const char* szPostfix = ""; + if(g_fDumpHTML) + { + szPrefix = "<B><FONT COLOR=NAVY>"; + szPostfix = "</FONT></B>"; + } + else if(g_fDumpRTF) + { + szPrefix = "\\b\\cf1 "; + szPostfix = "\\cf0\\b0 "; + } + if(szOrig == NULL) return szPrefix; + if(szOrig == (char*)-1) return szPostfix; + if(*szPrefix) + { + g_szBuf_KEYWORD->Shrink(0); + appendStr(g_szBuf_KEYWORD,szPrefix); + appendStr(g_szBuf_KEYWORD,szOrig); + appendStr(g_szBuf_KEYWORD,szPostfix); + return asString(g_szBuf_KEYWORD); + } + else + return szOrig; +} +const char* COMMENT(__in_opt __nullterminated const char* szOrig) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + const char* szPrefix = ""; + const char* szPostfix = ""; + if(g_fDumpHTML) + { + szPrefix = "<I><FONT COLOR=GREEN>"; + szPostfix = "</FONT></I>"; + } + else if(g_fDumpRTF) + { + szPrefix = "\\cf2\\i "; + szPostfix = "\\i0\\cf0 "; + } + else + { + szPrefix = ""; + szPostfix = ""; + } + if(szOrig == NULL) return szPrefix; + if(szOrig == (char*)-1) return szPostfix; + if(*szPrefix) + { + g_szBuf_COMMENT->Shrink(0); + appendStr(g_szBuf_COMMENT,szPrefix); + appendStr(g_szBuf_COMMENT,szOrig); + appendStr(g_szBuf_COMMENT,szPostfix); + return asString(g_szBuf_COMMENT); + } + else + return szOrig; +} +const char* ERRORMSG(__in_opt __nullterminated const char* szOrig) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + char* szPrefix = ""; + char* szPostfix = ""; + if(g_fDumpHTML) + { + szPrefix = "<I><B><FONT COLOR=RED>"; + szPostfix = "</FONT></B></I>"; + } + else if(g_fDumpRTF) + { + szPrefix = "\\cf3\\i\\b "; + szPostfix = "\\cf0\\b0\\i0 "; + } + if(szOrig == NULL) return szPrefix; + if(szOrig == (char*)-1) return szPostfix; + if(*szPrefix) + { + g_szBuf_ERRORMSG->Shrink(0); + appendStr(g_szBuf_ERRORMSG,szPrefix); + appendStr(g_szBuf_ERRORMSG,szOrig); + appendStr(g_szBuf_ERRORMSG,szPostfix); + return asString(g_szBuf_ERRORMSG); + } + else + return szOrig; +} + +const char* ANCHORPT(__in __nullterminated const char* szOrig, mdToken tk) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + if(g_fDumpHTML) + { + char szPrefix[64]; + const char* szPostfix = "</A>"; + sprintf_s(szPrefix, COUNTOF(szPrefix), "<A NAME=A%08X>",tk); + g_szBuf_ANCHORPT->Shrink(0); + appendStr(g_szBuf_ANCHORPT,szPrefix); + appendStr(g_szBuf_ANCHORPT,szOrig); + appendStr(g_szBuf_ANCHORPT,szPostfix); + return asString(g_szBuf_ANCHORPT); + } + else + return szOrig; +} +const char* JUMPPT(__in __nullterminated const char* szOrig, mdToken tk) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + if(g_fDumpHTML) + { + char szPrefix[64]; + const char* szPostfix = "</A>"; + sprintf_s(szPrefix,COUNTOF(szPrefix), "<A HREF=#A%08X>",tk); + g_szBuf_JUMPPT->Shrink(0); + appendStr(g_szBuf_JUMPPT,szPrefix); + appendStr(g_szBuf_JUMPPT,szOrig); + appendStr(g_szBuf_JUMPPT,szPostfix); + return asString(g_szBuf_JUMPPT); + } + else + return szOrig; +} +const char* SCOPE(void) { return g_fDumpRTF ? "\\{" : "{"; } +const char* UNSCOPE(void) { return g_fDumpRTF ? "\\}" : "}"; } +const char* LTN(void) { return g_fDumpHTML ? "<" : "<"; } +const char* GTN(void) { return g_fDumpHTML ? ">" : ">"; } +const char* AMP(void) { return g_fDumpHTML ? "&" : "&"; } + + + +/******************************************************************************/ +// Function: convert spec.symbols to esc sequences and single-quote if necessary +const char* UnquotedProperName(__in __nullterminated const char* name, unsigned len/*=(unsigned)-1*/) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + CQuickBytes *buff = g_szBuf_UnquotedProperName; + _ASSERTE (buff); + if(g_fUseProperName) + { + const char *pcn,*pcend,*ret; + if (name != NULL) + { + if (*name != 0) + { + pcn = name; + if (len == (unsigned)(-1)) + len = (unsigned)strlen(name); + pcend = pcn + len; + buff->Shrink(0); + for (pcn = name; pcn < pcend; pcn++) + { + switch(*pcn) + { + case '\t': appendChar(buff,'\\'); appendChar(buff,'t'); break; + case '\n': appendChar(buff,'\\'); appendChar(buff,'n'); break; + case '\b': appendChar(buff,'\\'); appendChar(buff,'b'); break; + case '\r': appendChar(buff,'\\'); appendChar(buff,'r'); break; + case '\f': appendChar(buff,'\\'); appendChar(buff,'f'); break; + case '\v': appendChar(buff,'\\'); appendChar(buff,'v'); break; + case '\a': appendChar(buff,'\\'); appendChar(buff,'a'); break; + case '\\': appendChar(buff,'\\'); appendChar(buff,'\\'); break; + case '\'': appendChar(buff,'\\'); appendChar(buff,'\''); break; + case '\"': appendChar(buff,'\\'); appendChar(buff,'\"'); break; + case '{': appendStr(buff,SCOPE()); break; + case '}': appendStr(buff,UNSCOPE()); break; + case '<': appendStr(buff,LTN()); break; + case '>': appendStr(buff,GTN()); break; + case '&': appendStr(buff,AMP()); break; + default: appendChar(buff,*pcn); + } + } + ret = asString(buff); + } + else ret = ""; + } + else ret = NULL; + return ret; + } + return name; +} +/******************************************************************************/ +// Function: convert spec.symbols to esc sequences and single-quote if necessary +const char* ProperName(__in __nullterminated const char* name, bool isLocalName) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + CQuickBytes *buff = g_szBuf_ProperName; + _ASSERTE (buff); + if(g_fUseProperName) + { + char *ret; + BOOL fQuoted; + if(name) + { + if(*name) + { + buff->Shrink(0); + fQuoted = isLocalName ? IsLocalToQuote(name) : IsNameToQuote(name); + if(fQuoted) appendChar(buff,'\''); + appendStr(buff,UnquotedProperName(name)); + if(fQuoted) appendChar(buff,'\''); + ret = asString(buff); + } + else ret = ""; + } + else ret = NULL; + return ret; + } + return name; +} diff --git a/src/ildasm/dasm_mi.cpp b/src/ildasm/dasm_mi.cpp new file mode 100644 index 0000000000..a2ae27a580 --- /dev/null +++ b/src/ildasm/dasm_mi.cpp @@ -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. +// + +#include "ildasmpch.h" + +#include "../tools/metainfo/mdinfo.cpp" +#include "../tools/metainfo/mdobj.cpp" diff --git a/src/ildasm/dasm_pr.cpp b/src/ildasm/dasm_pr.cpp new file mode 100644 index 0000000000..23f9ae1d3f --- /dev/null +++ b/src/ildasm/dasm_pr.cpp @@ -0,0 +1,274 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "ildasmpch.h" + +#include "resource.h" +#include "formattype.h" + +WCHAR* RstrW(unsigned id); + +extern HINSTANCE g_hInstance; +extern HINSTANCE g_hResources; +extern DWORD g_NumClasses; +extern char g_szInputFile[]; // in UTF-8 +extern char g_szOutputFile[]; // in UTF-8 + +#define IDC_CANCEL 101 + +HWND g_hwndProgress = NULL; +HWND g_hwndProgBox = NULL; +HWND g_hwndFromFile = NULL; +HWND g_hwndToFile = NULL; +HWND g_hwndTally = NULL; +HWND g_hwndCancel = NULL; +HANDLE g_hThreadReady = NULL; // event + +BOOL g_fInitCommonControls = TRUE; +BOOL g_fRegisterClass = TRUE; +ULONG g_ulCount, g_ulRange; +RECT rcClient; // client area of parent window + +WCHAR* UtfToUnicode(__in __nullterminated const char* sz); // defined in dis.cpp + +LRESULT CALLBACK ProgBoxWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + switch (uMsg) + { + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CANCEL: + g_hwndProgress = NULL; + g_hwndProgBox = NULL; + g_hwndFromFile = NULL; + g_hwndToFile = NULL; + g_hwndTally = NULL; + g_hwndCancel = NULL; + DestroyWindow (hwnd); + break; + } + break; + + + case WM_CLOSE: + g_hwndProgress = NULL; + g_hwndProgBox = NULL; + g_hwndFromFile = NULL; + g_hwndToFile = NULL; + g_hwndTally = NULL; + g_hwndCancel = NULL; + //break; + default: + return WszDefWindowProc(hwnd, uMsg, wParam, lParam); + } + return 0; +} +DWORD WINAPI ProgressMainLoop(LPVOID pv) +{ + MSG msg; + DWORD cyVScroll; + HFONT hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); //(ANSI_FIXED_FONT); + WCHAR wzStr[1024]; + + if(g_fInitCommonControls) + { + InitCommonControls(); + g_fInitCommonControls = FALSE; + } + g_ulCount = 0; + if(g_fRegisterClass) + { + _ASSERTE(g_hResources != NULL); + WNDCLASSW wndClass; + + wndClass.style = CS_HREDRAW|CS_VREDRAW|CS_NOCLOSE; + wndClass.lpfnWndProc = ProgBoxWndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = g_hInstance; + wndClass.hIcon = WszLoadIcon(g_hResources,MAKEINTRESOURCE(IDI_ICON2)); + wndClass.hCursor = NULL; + wndClass.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH); + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = L"ProgressBox"; + + if (WszRegisterClass(&wndClass) == 0) return 0; + + g_fRegisterClass = FALSE; + } + cyVScroll = GetSystemMetrics(SM_CYVSCROLL); + if(g_hwndProgBox = WszCreateWindowEx (0, + RstrW(IDS_PROGRESSBOX), //"ProgressBox", + RstrW(IDS_DISASSEMBLING), //"Disassembling", + WS_VISIBLE | WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_CLIPCHILDREN, + 400, 200, 400, 8*cyVScroll, + HWND_DESKTOP, + (HMENU)0, + g_hInstance, + NULL)) + { + GetClientRect(g_hwndProgBox, &rcClient); + + if(g_hwndFromFile = WszCreateWindowEx (0, + L"STATIC", + L"", + WS_CHILD|WS_VISIBLE|SS_CENTER, + rcClient.left, rcClient.bottom-6*cyVScroll,rcClient.right, cyVScroll, + g_hwndProgBox, + (HMENU)0, + g_hInstance, + NULL)) + { + SendMessageA(g_hwndFromFile,WM_SETFONT,(LPARAM)hFont,FALSE); + WCHAR* wzFileName = UtfToUnicode(g_szInputFile); + if(wcslen(wzFileName) <= 60) swprintf_s(wzStr,1024,RstrW(IDS_PB_FILE) /*"File %s"*/,wzFileName); + else + { + WCHAR * p=wzFileName; + while(p = wcschr(p,L'\\')) + { + if(wcslen(p) <= 60) break; + p++; + } + if(p == NULL) p = &wzFileName[wcslen(wzFileName)-50]; + swprintf_s(wzStr,1024,RstrW(IDS_PB_FILE1) /*"File ...%s"*/,p); + } + WszSendMessage(g_hwndFromFile, WM_SETTEXT,0,(LPARAM)wzStr); + } + if(g_hwndToFile = WszCreateWindowEx (0, + L"STATIC", + L"", + WS_CHILD|WS_VISIBLE|SS_CENTER, + rcClient.left, rcClient.bottom-5*cyVScroll,rcClient.right, cyVScroll, + g_hwndProgBox, + (HMENU)0, + g_hInstance, + NULL)) + { + SendMessageA(g_hwndToFile,WM_SETFONT,(LPARAM)hFont,FALSE); + WCHAR* wzFileName = UtfToUnicode(g_szOutputFile); + if(wcslen(wzFileName) <= 60) swprintf_s(wzStr,1024,RstrW(IDS_PB_TOFILE) /*"To file %s"*/,wzFileName); + else + { + WCHAR * p=wzFileName; + while(p = wcschr(p,L'\\')) + { + if(wcslen(p) <= 60) break; + p++; + } + if(p == NULL) p = &wzFileName[wcslen(wzFileName)-50]; + swprintf_s(wzStr,1024,RstrW(IDS_PB_TOFILE1) /*"To file ...%s"*/,p); + } + WszSendMessage(g_hwndToFile, WM_SETTEXT,0,(LPARAM)wzStr); + } + if(g_hwndTally = WszCreateWindowEx (0, + L"STATIC", + L"", + WS_CHILD|WS_VISIBLE|SS_CENTER, + rcClient.left, rcClient.bottom-4*cyVScroll,rcClient.right, cyVScroll, + g_hwndProgBox, + (HMENU)0, + g_hInstance, + NULL)) + { + SendMessageA(g_hwndTally,WM_SETFONT,(LPARAM)hFont,FALSE); + if(g_ulCount <= g_NumClasses) swprintf_s(wzStr,1024,RstrW(IDS_PB_CLASSESDONE) /*"%d classes, %d done"*/,g_NumClasses,g_ulCount); + else swprintf_s(wzStr,1024,RstrW(IDS_PB_GLOBALSDONE) /*"%d global methods, %d done"*/,g_ulRange-g_NumClasses,g_ulCount-g_NumClasses); + WszSendMessage(g_hwndTally, WM_SETTEXT,0,(LPARAM)wzStr); + } + if(g_hwndProgress = WszCreateWindowEx (0, + PROGRESS_CLASS, + L"", + WS_CHILD|WS_VISIBLE|SS_CENTER, // SS_CENTER gives smooth progress and solid bar + rcClient.left, rcClient.bottom-3*cyVScroll,rcClient.right, cyVScroll, + g_hwndProgBox, + (HMENU)0, + g_hInstance, + NULL)) + { + // Set the range for the progress bar. + SendMessageA (g_hwndProgress, PBM_SETRANGE, 0L, MAKELPARAM(0, g_ulRange)); + // Set the step. + SendMessageA (g_hwndProgress, PBM_SETSTEP, (WPARAM)1, 0L); + } + if(g_hwndCancel = WszCreateWindowEx (0, + L"BUTTON", + RstrW(IDS_PB_CANCEL), //"Cancel", + WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON|BS_TEXT, + rcClient.left+150, rcClient.bottom-3*cyVScroll/2,rcClient.right-300, 4*cyVScroll/3, + g_hwndProgBox, + (HMENU)IDC_CANCEL, + g_hInstance, + NULL)) + { + SendMessageA(g_hwndCancel,WM_SETFONT,(LPARAM)hFont,FALSE); + } + } + SetEvent(g_hThreadReady); + while (WszGetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + WszDispatchMessage(&msg); + } + return 0; +} + +void CreateProgressBar(LONG lRange) +{ + DWORD dwThreadID; + g_ulCount = 0; + if((g_ulRange = (ULONG)lRange)==0) return; + + g_hThreadReady = WszCreateEvent(NULL,FALSE,FALSE,NULL); + if (g_hThreadReady != NULL) + { + // Thread is never aborted, it always exits by itself + HANDLE hThread = CreateThread(NULL,0,ProgressMainLoop,NULL,0,&dwThreadID); + if (hThread != NULL) + { + CloseHandle(hThread); + WaitForSingleObject(g_hThreadReady,INFINITE); + } + CloseHandle(g_hThreadReady); + } +} + +BOOL ProgressStep() +{ + if(g_hwndProgBox) + { + WCHAR wzStr[1024]; + if(g_hwndTally) + { + if(g_ulCount <= g_NumClasses) + swprintf_s(wzStr,1024,RstrW(IDS_PB_CLASSESDONE) /*"%d classes, %d done"*/,g_NumClasses,g_ulCount); + else if(g_ulCount <= g_ulRange) + swprintf_s(wzStr,1024,RstrW(IDS_PB_GLOBALSDONE) /*"%d global methods, %d done"*/,g_ulRange-g_NumClasses,g_ulCount-g_NumClasses); + else + wcscpy_s(wzStr,1024,RstrW(IDS_PB_WRITINGDATA)); //"Writing global data"); + wzStr[1023]=0; + WszSendMessage(g_hwndTally, WM_SETTEXT,0,(LPARAM)wzStr); + } + + if(g_hwndProgress && g_ulCount && (g_ulCount <= g_ulRange)) + WszSendMessage (g_hwndProgress, PBM_STEPIT, 0L, 0L); + g_ulCount++; + } + else if(g_ulCount) return FALSE; // disassembly started and was aborted + return TRUE; +} + +void DestroyProgressBar() +{ + if(g_hwndProgBox) WszSendMessage (g_hwndProgBox,WM_COMMAND,IDC_CANCEL,0); + g_hwndProgress = NULL; + g_hwndProgBox = NULL; + g_hwndFromFile = NULL; + g_hwndToFile = NULL; + g_hwndTally = NULL; + g_hwndCancel = NULL; + g_ulCount = 0; +} diff --git a/src/ildasm/dasm_sz.cpp b/src/ildasm/dasm_sz.cpp new file mode 100644 index 0000000000..036c521ca9 --- /dev/null +++ b/src/ildasm/dasm_sz.cpp @@ -0,0 +1,230 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "ildasmpch.h" + +#include <metadata.h> +#include <utilcode.h> +#include "debugmacros.h" +#include "dasm_sz.h" +#include "ceeload.h" + +extern PELoader *g_pPELoader; + +unsigned SizeOfValueType(mdToken tk, IMDInternalImport* pImport) +{ + unsigned ret = 0xFFFFFFFF; + if((TypeFromToken(tk)==mdtTypeDef)&&RidFromToken(tk)&&pImport) + { + DWORD dwAttrs; + mdToken tkExtends; + if (FAILED(pImport->GetTypeDefProps(tk, &dwAttrs, &tkExtends))) + { + return ret; + } + if(!(IsTdInterface(dwAttrs)||IsTdAbstract(dwAttrs)||IsTdImport(dwAttrs))) + { + mdToken tkField; + DWORD dwFieldAttrs; + unsigned uFieldSize; + ULONG ulPack=0, + ulSize = 0, + ulInstFieldSize = 0; + + if (FAILED(pImport->GetClassPackSize(tk,&ulPack))) ulPack = 0; + if (FAILED(pImport->GetClassTotalSize(tk,&ulSize))) ulSize = 0; + + if (IsTdExplicitLayout(dwAttrs)) + { + MD_CLASS_LAYOUT hLayout; + if (SUCCEEDED(pImport->GetClassLayoutInit(tk,&hLayout))) + { + ULONG ulOffset; + while (SUCCEEDED(pImport->GetClassLayoutNext(&hLayout,&tkField,&ulOffset)) && RidFromToken(tkField)) + { + if (FAILED(pImport->GetFieldDefProps(tkField, &dwFieldAttrs))) + { + break; + } + if (!(IsFdStatic(dwFieldAttrs)||IsFdLiteral(dwFieldAttrs))) + { + uFieldSize = SizeOfField(tkField,pImport); + if (uFieldSize == 0xFFFFFFFF) return uFieldSize; + uFieldSize += ulOffset; + if (uFieldSize > ulInstFieldSize) ulInstFieldSize = uFieldSize; + } + } + } + } + else + { + HENUMInternal hEnumField; + unsigned cFieldsMax = 0; + if (SUCCEEDED(pImport->EnumInit(mdtFieldDef, tk, &hEnumField))) + { + if ((cFieldsMax = pImport->EnumGetCount(&hEnumField)) != 0) + { + while (pImport->EnumNext(&hEnumField, &tkField) && RidFromToken(tkField)) + { + if (FAILED(pImport->GetFieldDefProps(tkField, &dwFieldAttrs))) + { + break; + } + if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs)) + { + uFieldSize = SizeOfField(tkField,pImport); + if (uFieldSize == 0xFFFFFFFF) return uFieldSize; + if (ulPack > 1) + { + ULONG ulDelta = ulInstFieldSize % ulPack; + if (ulDelta != 0) ulInstFieldSize += ulPack - ulDelta; + } + ulInstFieldSize += uFieldSize; + } + } + } + pImport->EnumClose(&hEnumField); + } + } + ret = (ulInstFieldSize > ulSize) ? ulInstFieldSize : ulSize; + if(ret == 0) ret = 1; // zero-sized value types automatically get 1 byte + } + } + return ret; +} + +unsigned SizeOfField(mdToken tk, IMDInternalImport* pImport) +{ + unsigned ret = 0xFFFFFFFF; + if((TypeFromToken(tk) == mdtFieldDef) && RidFromToken(tk) && pImport) + { + PCCOR_SIGNATURE pSig; + ULONG cSig; + if (FAILED(pImport->GetSigOfFieldDef(tk, &cSig, &pSig))) + { + return ret; + } + ret = SizeOfField(&pSig,cSig,pImport); + } + return ret; +} + +unsigned SizeOfField(PCCOR_SIGNATURE *ppSig, ULONG cSig, IMDInternalImport* pImport) +{ + unsigned ret = 0xFFFFFFFF; + if(ppSig && *ppSig && cSig && pImport) + { + unsigned callConv = CorSigUncompressData(*ppSig); + if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD)) + { + mdToken tk; + int typ; + BOOL Reiterate; + unsigned uElementNumber = 1; + PCCOR_SIGNATURE pSigStart = *ppSig; + PCCOR_SIGNATURE pSigEnd = *ppSig+cSig; + + // Size of the pointer depends on bitness of the assembly + unsigned nSizeOfPointer = g_pPELoader->IsPE32() ? 4 : 8; + + do { + Reiterate = FALSE; + switch(typ = *(*ppSig)++) { + case ELEMENT_TYPE_VOID : + return 0; + + case ELEMENT_TYPE_I1 : + case ELEMENT_TYPE_U1 : + case ELEMENT_TYPE_BOOLEAN : + return uElementNumber; + + case ELEMENT_TYPE_CHAR : + case ELEMENT_TYPE_I2 : + case ELEMENT_TYPE_U2 : + return (uElementNumber << 1); + + case ELEMENT_TYPE_I4 : + case ELEMENT_TYPE_U4 : + case ELEMENT_TYPE_R4 : + return (uElementNumber << 2); + + case ELEMENT_TYPE_I8 : + case ELEMENT_TYPE_U8 : + case ELEMENT_TYPE_R8 : + return (uElementNumber << 3); + + case ELEMENT_TYPE_OBJECT : + case ELEMENT_TYPE_STRING : + case ELEMENT_TYPE_FNPTR : + case ELEMENT_TYPE_CLASS : + case ELEMENT_TYPE_PTR : + case ELEMENT_TYPE_BYREF : + //case ELEMENT_TYPE_VAR : + case ELEMENT_TYPE_U : + case ELEMENT_TYPE_I : + return (uElementNumber * nSizeOfPointer); + + case ELEMENT_TYPE_TYPEDBYREF : // pair of ptrs + return (uElementNumber * nSizeOfPointer * 2); + + case ELEMENT_TYPE_VALUETYPE : + *ppSig += CorSigUncompressToken(*ppSig, &tk); + ret = SizeOfValueType(tk,pImport); + if(ret != 0xFFFFFFFF) ret *= uElementNumber; + return ret; + + // Modifiers or depedant types + + case ELEMENT_TYPE_ARRAY : + ret = SizeOfField(ppSig, cSig-(unsigned)((*ppSig)-pSigStart), pImport); + if(ret != 0xFFFFFFFF) + { + unsigned rank = CorSigUncompressData(*ppSig); + if (rank == 0) ret = 0xFFFFFFFF; + else + { + int* lowerBounds = new (nothrow) int[2*rank]; + int* sizes = &lowerBounds[rank]; + memset(lowerBounds, 0, sizeof(int)*2*rank); + + unsigned numSizes = CorSigUncompressData(*ppSig); + _ASSERTE(numSizes <= rank); + unsigned i; + for(i =0; i < numSizes; i++) + sizes[i] = CorSigUncompressData(*ppSig); + + unsigned numLowBounds = CorSigUncompressData(*ppSig); + _ASSERTE(numLowBounds <= rank); + for(i = 0; i < numLowBounds; i++) + *ppSig+=CorSigUncompressSignedInt(*ppSig,&lowerBounds[i]); + + for(i = 0; i < numSizes; i++) + { + if (sizes[i]) uElementNumber *= sizes[i]; + } + ret *= uElementNumber; + delete[] lowerBounds; + } + } + return ret; + + case ELEMENT_TYPE_CMOD_OPT : + case ELEMENT_TYPE_CMOD_REQD : + *ppSig += CorSigUncompressToken(*ppSig, &tk); + case ELEMENT_TYPE_PINNED : + case ELEMENT_TYPE_SZARRAY : // uElementNumber doesn't change + if(*ppSig < pSigEnd) Reiterate = TRUE; + break; + + default: + case ELEMENT_TYPE_SENTINEL : + case ELEMENT_TYPE_END : + break; + } // end switch + } while(Reiterate); + } // end if(CALLCONV_FIELD) + } // end if(signature && import) + return ret; +} diff --git a/src/ildasm/dasm_sz.h b/src/ildasm/dasm_sz.h new file mode 100644 index 0000000000..d1682bf225 --- /dev/null +++ b/src/ildasm/dasm_sz.h @@ -0,0 +1,15 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _DASM_SZ_H_ +#define _DASM_SZ_H_ + +unsigned SizeOfValueType(mdToken tk, IMDInternalImport* pImport); + +unsigned SizeOfField(mdToken tk, IMDInternalImport* pImport); + +unsigned SizeOfField(PCCOR_SIGNATURE *ppSig, ULONG cSig, IMDInternalImport* pImport); + +#endif diff --git a/src/ildasm/dasmenum.hpp b/src/ildasm/dasmenum.hpp new file mode 100644 index 0000000000..f636fe47ca --- /dev/null +++ b/src/ildasm/dasmenum.hpp @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "openum.h" + +typedef struct +{ + const char * pszName; + + OPCODE Ref; // reference codes + + BYTE Type; // Inline0 etc. + + BYTE Len; // std mapping + BYTE Std1; + BYTE Std2; +} opcodeinfo_t; + +#ifdef DECLARE_DATA +opcodeinfo_t OpcodeInfo[] = +{ +#define OPDEF(c,s,pop,push,args,type,l,s1,s2,ctrl) { s,c,args,l,s1,s2 }, +#include "opcode.def" +#undef OPDEF +}; +#else +extern opcodeinfo_t OpcodeInfo[]; +#endif + + diff --git a/src/ildasm/dasmgui.h b/src/ildasm/dasmgui.h new file mode 100644 index 0000000000..990cec0433 --- /dev/null +++ b/src/ildasm/dasmgui.h @@ -0,0 +1,16 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +BOOL CreateGUI(); +void GUISetModule(__in __nullterminated const char *pszModule); +void GUIMainLoop(); +void GUIAddOpcode(__inout_opt __nullterminated const char *szString, __in_opt void *GUICookie); +BOOL GUIAddItemsToList(); +void GUIAddOpcode(__inout __nullterminated const char *szString); +void DestroyGUI(); +UINT GetDasmMBRTLStyle(); + +BOOL DisassembleMemberByName(__in __nullterminated const char *pszClassName, __in __nullterminated const char *pszMemberName, __in __nullterminated const char *pszSig); +BOOL IsGuiILOnly(); diff --git a/src/ildasm/dasmhlp.hhc b/src/ildasm/dasmhlp.hhc new file mode 100644 index 0000000000..dcedac2abb --- /dev/null +++ b/src/ildasm/dasmhlp.hhc @@ -0,0 +1,32 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<HTML> +<HEAD> +<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1"> +<!-- Sitemap 1.0 --> +</HEAD><BODY> +<OBJECT type="text/site properties"> + <param name="Window Styles" value="0x800021"> +</OBJECT> +<UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Menu Options"> + <param name="Local" value="html\menu_options.htm"> + <param name="URL" value="html\menu_options.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Tree View Icons"> + <param name="Local" value="html\tree_view_icons.htm"> + <param name="URL" value="html\tree_view_icons.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Clicking on Tree View Items"> + <param name="Local" value="html\clicking.htm"> + <param name="URL" value="html\clicking.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Keyboard Commands"> + <param name="Local" value="html\keyboard.htm"> + <param name="URL" value="html\keyboard.htm"> + </OBJECT> +</UL> +</BODY></HTML> diff --git a/src/ildasm/dirs.proj b/src/ildasm/dirs.proj new file mode 100644 index 0000000000..86d561e3f8 --- /dev/null +++ b/src/ildasm/dirs.proj @@ -0,0 +1,15 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + <!--Leaf project Properties--> + <!--The following projects will build during PHASE 1--> + <PropertyGroup> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildInPhase1>true</BuildInPhase1> + </PropertyGroup> + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Include="exe\ildasm.nativeproj" /> + <ProjectFile Include="rcdll\ildasmrc.nativeproj" /> + </ItemGroup> + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> diff --git a/src/ildasm/dis.cpp b/src/ildasm/dis.cpp new file mode 100644 index 0000000000..4356b6f40a --- /dev/null +++ b/src/ildasm/dis.cpp @@ -0,0 +1,2787 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// Disassembler +// +#include "ildasmpch.h" + +#include "debugmacros.h" +#include "corpriv.h" +#include "dasmenum.hpp" +#include "dasmgui.h" +#include "formattype.h" +#include "dis.h" +#include "resource.h" +#include "ilformatter.h" +#include "outstring.h" + +#include "ceeload.h" +#include "dynamicarray.h" +extern PELoader * g_pPELoader; +#include <corsym.h> + +extern ISymUnmanagedReader* g_pSymReader; +extern BOOL g_fDumpAsmCode; +extern char g_szAsmCodeIndent[]; +extern BOOL g_fShowBytes; +extern BOOL g_fShowSource; +extern BOOL g_fInsertSourceLines; +extern BOOL g_fTryInCode; +extern BOOL g_fQuoteAllNames; +extern BOOL g_fDumpTokens; +extern DynamicArray<__int32> *g_pPtrTags; //to keep track of all "ldptr" +extern DynamicArray<DWORD> *g_pPtrSize; //to keep track of all "ldptr" +extern int g_iPtrCount; +static BOOL ConvToLiteral(__inout __nullterminated char* retBuff, const WCHAR* str, int cbStr); +extern DWORD g_Mode; +extern unsigned g_uConsoleCP; + +#define PADDING 28 + +extern BOOL g_fThisIsInstanceMethod; +extern unsigned g_uCodePage; +extern HANDLE hConsoleOut; +extern HANDLE hConsoleErr; +// globals for source file info +ULONG_PTR ulWasFileToken = 0xFFFFFFFF; +GUID guidWasLang={0}, guidWasLangVendor={0},guidWasDoc={0}; +WCHAR wzWasFileName[2048]; +ULONG ulWasLine = 0; +FILE* pFile=NULL; +BOOL bIsNewFile = TRUE; +WCHAR wzUniBuf[UNIBUF_SIZE]; +char szString[SZSTRING_SIZE]; +//----------------------------------- +struct LexScope +{ + DWORD dwStart; + DWORD dwEnd; + ISymUnmanagedScope* pISymScope; + DWORD dwZOrder; + inline bool IsOpen() { return (dwZOrder != 0); }; + inline bool Covers(DWORD dwOffset) { return ((dwStart <= dwOffset) && (dwOffset < dwEnd)); }; +}; +//----------------------------------- + +OPCODE DecodeOpcode(const BYTE *pCode, DWORD *pdwLen) +{ + OPCODE opcode; + + *pdwLen = 1; + opcode = OPCODE(pCode[0]); + switch(opcode) { + case CEE_PREFIX1: + opcode = OPCODE(pCode[1] + 256); + if (opcode < 0 || opcode >= CEE_COUNT) + opcode = CEE_COUNT; + *pdwLen = 2; + break; + case CEE_PREFIXREF: + case CEE_PREFIX2: + case CEE_PREFIX3: + case CEE_PREFIX4: + case CEE_PREFIX5: + case CEE_PREFIX6: + case CEE_PREFIX7: + *pdwLen = 3; + return CEE_COUNT; + default: + break; + } + return opcode; +} +//------------------------------------------------------------------ +WCHAR* UtfToUnicode(__in __nullterminated const char* sz) +{ + WCHAR* wz = wzUniBuf; + if (WszMultiByteToWideChar(CP_UTF8,0,sz,-1,wz,UNIBUF_SIZE/2) == 0) + { + wz[UNIBUF_SIZE/2 - 1] = 0; + } + return wz; +} +char* UnicodeToAnsi(__in __nullterminated const WCHAR* wz) +{ + char* sz = (char*)(&wzUniBuf[UNIBUF_SIZE/2]); + if (WszWideCharToMultiByte(g_uConsoleCP,0,wz,-1,sz,UNIBUF_SIZE,NULL,NULL) == 0) + { + sz[UNIBUF_SIZE - 1] = 0; + } + return sz; +} +WCHAR* AnsiToUnicode(__in __nullterminated const char* sz) +{ + WCHAR* wz = wzUniBuf; + if (WszMultiByteToWideChar(g_uConsoleCP,0,sz,-1,wz,UNIBUF_SIZE/2) == 0) + { + wz[UNIBUF_SIZE/2 - 1] = 0; + } + return wz; +} +char* UnicodeToUtf(__in __nullterminated const WCHAR* wz) +{ + char* sz = (char*)(&wzUniBuf[UNIBUF_SIZE/2]); + if (WszWideCharToMultiByte(CP_UTF8,0,wz,-1,sz,UNIBUF_SIZE,NULL,NULL) == 0) + { + sz[UNIBUF_SIZE - 1] = 0; + } + return sz; +} +char* AnsiToUtf(__in __nullterminated const char* sz) { return UnicodeToUtf(AnsiToUnicode(sz));} + +static void UnicodeToConsoleOrMsgBox(__in __nullterminated const WCHAR* wz) +{ + if (g_Mode & MODE_GUI) + WszMessageBox(NULL,wz,RstrW(IDS_ERRORCAPTION),MB_OK|MB_ICONERROR|GetDasmMBRTLStyle()); + else + { + //DWORD dw; + //char* sz = UnicodeToAnsi(wz); + //WriteFile(hConsoleOut,(CONST VOID *)sz, (ULONG32)strlen(sz),&dw,NULL); + //WriteFile(hConsoleOut,(CONST VOID *)"\r\n", 2,&dw,NULL); + printf("%s\n",UnicodeToAnsi(wz)); + } +} +static void UnicodeToFile(__in __nullterminated const WCHAR* wz, FILE* pF) +{ + unsigned endofline = 0x000A000D; + int L; + if((L=(int)wcslen(wz))) fwrite(wz,L*sizeof(WCHAR),1,pF); + fwrite(&endofline,4,1,pF); +} +static void ToGUIOrFile(__in __nullterminated const char* sz, void* GUICookie) +{ + if (g_Mode & MODE_GUI) + GUIAddOpcode(sz, GUICookie); + else + { + if(g_fDumpRTF) fprintf((FILE*)GUICookie,"%s\\line\n",sz); + else fprintf((FILE*)GUICookie,"%s\n",sz); + } +} +//------------------------------------------------------------------ +void printError(void* GUICookie, __in __nullterminated const char* string) +{ + if(g_Mode & MODE_GUI) printLine(GUICookie, ERRORMSG(string)); + else + { + //DWORD dw; + const char* sz = ERRORMSG(string); + if(GUICookie) printLine(GUICookie, sz); + //sz = UnicodeToAnsi(UtfToUnicode(string)); + //WriteFile(hConsoleErr,(CONST VOID *)sz, (ULONG32)strlen(sz),&dw,NULL); + //WriteFile(hConsoleErr,(CONST VOID *)"\r\n", 2,&dw,NULL); + fprintf(stderr,"%s\n",UnicodeToAnsi(UtfToUnicode(string))); + } +} +void printLine(void* GUICookie, __in __nullterminated const char* string) +{ + const char* sz = string; + + if (GUICookie == NULL) + { + UnicodeToConsoleOrMsgBox(UtfToUnicode(string)); + return; + } + + + if(g_uCodePage != CP_UTF8) + { + WCHAR* wz = UtfToUnicode(string); + if(g_uCodePage != 0xFFFFFFFF) + { + sz = UnicodeToAnsi(wz); + } + else if(GUICookie && (!(g_Mode & MODE_GUI))) + { + UnicodeToFile(wz,(FILE*)GUICookie); + return; + } + else sz = (char*)wz; + } + ToGUIOrFile(sz,GUICookie); +} + +void printLineW(void* GUICookie, __in __nullterminated const WCHAR* string) +{ + const char* sz = (const char*)string; + + if (GUICookie == NULL) + { + UnicodeToConsoleOrMsgBox(string); + return; + } + if(g_uCodePage == 0xFFFFFFFF) + { + if(!(g_Mode & MODE_GUI)) + { + UnicodeToFile(string,(FILE*)GUICookie); + return; + } + } + else if(g_uCodePage == CP_UTF8) + sz = UnicodeToUtf(string); + else if(g_uCodePage == g_uConsoleCP) + sz = UnicodeToAnsi(string); + + ToGUIOrFile(sz,GUICookie); +} + +char * DumpQString(void* GUICookie, + __in __nullterminated const char* szToDump, + __in __nullterminated const char* szPrefix, + unsigned uMaxLen) +{ + unsigned Lwt = (unsigned)strlen(szString); + char* szptr = &szString[Lwt]; + const char* p = szToDump; + unsigned L = (unsigned)strlen(szToDump); + unsigned l,i; + unsigned tally=0; + *szptr++ = '"'; + + do + { + l = L; + if(l > uMaxLen+2) // +2 - to account for leading/trailing doublequotes in szToDump + { + l = uMaxLen; + while((p[l-1] == '\\')&& l) l--; + if(l == 0) l = (uMaxLen+1) & 0xFFFFFFFE; + } + if(tally) + { + printLine(GUICookie,szString); + szptr = szString; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s+ \"",szPrefix); + } + else uMaxLen = uMaxLen - (ULONG32)strlen(szPrefix) + Lwt; + tally++; + for(i=0; i < l; i++, szptr++, p++) + { + switch(*p) + { + case '\n': *szptr++ = '\\'; *szptr = 'n'; break; + case '\r': *szptr++ = '\\'; *szptr = 'r'; break; + case '\t': *szptr++ = '\\'; *szptr = 't'; break; + case '\b': *szptr++ = '\\'; *szptr = 'b'; break; + case '\f': *szptr++ = '\\'; *szptr = 'f'; break; + case '\v': *szptr++ = '\\'; *szptr = 'v'; break; + case '\a': *szptr++ = '\\'; *szptr = 'a'; break; + case '\?': *szptr++ = '\\'; *szptr = '?'; break; + case '\\': *szptr++ = '\\'; *szptr = '\\'; break; + case '"': *szptr++ = '\\'; *szptr = '"'; break; + case '{': szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),SCOPE()); szptr--; break; + case '}': szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),UNSCOPE()); szptr--; break; + case '<': szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),LTN()); szptr--; break; + case '>': szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),GTN()); szptr--; break; + default: *szptr = *p; break; + } + } + *szptr++ = '"'; + *szptr = 0; + L -= l; + } while(L); + return szptr; +} +struct DasmExceptionInfoClause : COR_ILMETHOD_SECT_EH_CLAUSE_FAT { +public: + bool ClauseIsFat; +}; +DasmExceptionInfoClause* g_ehInfo = NULL; +ULONG g_ehCount = 0; +/********************************************************************************/ +/* used by qsort to sort the g_ehInfo table */ +static int __cdecl ehInfoCmp(const void *op1, const void *op2) +{ + DasmExceptionInfoClause* p1 = (DasmExceptionInfoClause*)op1; + DasmExceptionInfoClause* p2 = (DasmExceptionInfoClause*)op2; + int d; + d = p1->GetTryOffset() - p2->GetTryOffset(); if(d) return d; + d = p1->GetTryLength() - p2->GetTryLength(); if(d) return d; + d = p1->GetHandlerOffset() - p2->GetHandlerOffset(); if(d) return d; + d = p1->GetHandlerLength() - p2->GetHandlerLength(); if(d) return d; + return 0; +} + +BOOL enumEHInfo(const COR_ILMETHOD_SECT_EH* eh, IMDInternalImport *pImport, DWORD dwCodeSize) +{ + COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehBuff; + const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo; + BOOL fTryInCode = FALSE; + if(g_ehInfo) VDELETE(g_ehInfo); + g_ehCount = 0; + if(eh && (g_ehCount = eh->EHCount())) + { + g_ehInfo = new DasmExceptionInfoClause[g_ehCount]; + _ASSERTE(g_ehInfo != NULL); + unsigned i; + for (i = 0; i < g_ehCount; i++) + { + ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)eh->EHClause(i, &ehBuff); + memcpy(&g_ehInfo[i],ehInfo,sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_FAT)); + g_ehInfo[i].ClauseIsFat = eh->IsFat(); + //_ASSERTE((ehInfo->GetFlags() & SEH_NEW_PUT_MASK) == 0); // we are using 0x80000000 and 0x40000000 + g_ehInfo[i].SetFlags((CorExceptionFlag)((int)ehInfo->GetFlags() & ~SEH_NEW_PUT_MASK)); + } + // check if all boundaries are within method code: + fTryInCode = g_fTryInCode; + for(i=0; i < g_ehCount; i++) + { + if( (g_ehInfo[i].GetTryOffset() >= dwCodeSize) || + (g_ehInfo[i].GetTryOffset() + g_ehInfo[i].GetTryLength() >= dwCodeSize)|| + (g_ehInfo[i].GetHandlerOffset() >= dwCodeSize) || + (g_ehInfo[i].GetHandlerOffset() + g_ehInfo[i].GetHandlerLength() > dwCodeSize)) + { + g_ehInfo[i].SetFlags((CorExceptionFlag)((int)g_ehInfo[i].GetFlags() | ERR_OUT_OF_CODE)); + fTryInCode = FALSE; // if out of code, don't expand + } + } + + if(fTryInCode) + { + DWORD dwWasTryOffset=0xFFFFFFFF, dwWasTryLength=0xFFFFFFFF, dwLastOffset=0xFFFFFFFF; + unsigned iNewTryBlock=0; + qsort(g_ehInfo, g_ehCount, sizeof(DasmExceptionInfoClause), ehInfoCmp); + for(i=0; i < g_ehCount; i++) + { + if((g_ehInfo[i].GetTryOffset() != dwWasTryOffset)||(g_ehInfo[i].GetTryLength() != dwWasTryLength)) + { + g_ehInfo[i].SetFlags((CorExceptionFlag)((int)g_ehInfo[i].GetFlags() | NEW_TRY_BLOCK)); // insert try in source + dwLastOffset = g_ehInfo[i].GetTryOffset() + g_ehInfo[i].GetTryLength(); + dwWasTryOffset = g_ehInfo[i].GetTryOffset(); + dwWasTryLength = g_ehInfo[i].GetTryLength(); + iNewTryBlock = i; + } + + // determine offset of the block that lexically follows the try block (filter or handler) + DWORD dwFilterOrHandlerOffset; + if (g_ehInfo[i].GetFlags() & COR_ILEXCEPTION_CLAUSE_FILTER) + { + dwFilterOrHandlerOffset = g_ehInfo[i].GetFilterOffset(); + } + else + dwFilterOrHandlerOffset = g_ehInfo[i].GetHandlerOffset(); + + if (dwFilterOrHandlerOffset == dwLastOffset) + { + if((i == iNewTryBlock)||((int)g_ehInfo[iNewTryBlock].GetFlags() & PUT_INTO_CODE)) + g_ehInfo[i].SetFlags((CorExceptionFlag)((int)g_ehInfo[i].GetFlags() | PUT_INTO_CODE)); // insert catch/filter/finally in source + else + g_ehInfo[i].SetFlags((CorExceptionFlag)((int)g_ehInfo[i].GetFlags() | NEW_TRY_BLOCK)); // insert catch/filter/finally in source + + dwLastOffset = (g_ehInfo[i].GetHandlerOffset() + g_ehInfo[i].GetHandlerLength()); + } + else + g_ehInfo[i].SetFlags((CorExceptionFlag)((int)g_ehInfo[i].GetFlags() | NEW_TRY_BLOCK)); // insert try in source + } + } + else + { + for(i=0; i < g_ehCount; i++) + { + g_ehInfo[i].SetFlags((CorExceptionFlag)((int)g_ehInfo[i].GetFlags() | NEW_TRY_BLOCK)); // insert try in source + } + } + } + return fTryInCode; +} + +// This dumps the hex bytes for the given EHINFO clause +void DumpHexEHInfo(DasmExceptionInfoClause *ehInfo, void *GUICookie) +{ + char *szptr = &szString[0]; + _ASSERTE(g_fShowBytes); + COR_ILMETHOD_SECT_EH_CLAUSE_SMALL eh; // Temporary holder if we should dump the small version + BYTE *pb; + size_t sizeToDump; // Size of the hex data we're dumping + + szptr = &szString[0]; + szptr += sprintf_s(szptr, SZSTRING_SIZE,"%s// HEX:", g_szAsmCodeIndent); + ehInfo->SetFlags((CorExceptionFlag)((int)ehInfo->GetFlags() & ~SEH_NEW_PUT_MASK)); + + if (ehInfo->ClauseIsFat) + { + // Easy, though probably less common case + pb = (BYTE *)ehInfo; + sizeToDump = sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_FAT); + } else + { + // Dev11 #2227 - we should dump small clauses as such in the hex dump + // Recreate the small EH clause, here, if it came is as a small clause + eh.SetFlags(ehInfo->GetFlags()); + eh.TryOffset = ehInfo->TryOffset; + eh.TryLength = ehInfo->TryLength; + eh.HandlerOffset = ehInfo->HandlerOffset; + eh.HandlerLength = ehInfo->HandlerLength; + + // A couple of sanity checks to make sure things the hex bites recreated are alright + _ASSERTE(sizeof(eh.FilterOffset) == sizeof(eh.ClassToken)); + _ASSERTE(offsetof(COR_ILMETHOD_SECT_EH_CLAUSE_SMALL, FilterOffset) == offsetof(COR_ILMETHOD_SECT_EH_CLAUSE_SMALL, ClassToken)); + eh.FilterOffset = ehInfo->FilterOffset; + + pb = (BYTE *)&eh; + sizeToDump = sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_SMALL); + } + // Now dump the bytes out + for (size_t i = 0; i < sizeToDump; i++) + szptr += sprintf_s(szptr, SZSTRING_REMAINING_SIZE(szptr), " %2.2X", *pb++); + printLine(GUICookie, COMMENT(szString)); + // ehInfo->SetFlags((CorExceptionFlag)((dwFlags & ~SEH_NEW_PUT_MASK) | PUT_INTO_CODE)); +} + +void dumpOneEHInfo(DasmExceptionInfoClause* ehInfo, IMDInternalImport *pImport, void *GUICookie) +{ + //char szString[4096]; + char* szptr = &szString[0]; + if(!ehInfo) return; + DWORD dwFlags = ehInfo->GetFlags(); + if(dwFlags & PUT_INTO_CODE) + return; // by the time dumpEHInfo is called, this ehInfo is done + if(dwFlags & NEW_TRY_BLOCK) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%s IL_%04x ",g_szAsmCodeIndent,KEYWORD(".try"),ehInfo->GetTryOffset()); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s IL_%04x ",KEYWORD("to"),ehInfo->GetTryOffset()+ehInfo->GetTryLength()); + } + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s ",g_szAsmCodeIndent); + + if (dwFlags & COR_ILEXCEPTION_CLAUSE_FILTER) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%s IL_%04x ",KEYWORD("filter"),ehInfo->GetFilterOffset()); + else if (dwFlags & COR_ILEXCEPTION_CLAUSE_FAULT) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), KEYWORD("fault ")); + else if (dwFlags & COR_ILEXCEPTION_CLAUSE_FINALLY || IsNilToken(ehInfo->GetClassToken())) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), KEYWORD("finally ")); + else + { + CQuickBytes out; + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%s %s ",KEYWORD("catch"),PrettyPrintClass(&out, ehInfo->GetClassToken(), pImport)); + REGISTER_REF(g_tkRefUser,ehInfo->GetClassToken()); + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%s IL_%04x",KEYWORD("handler"),ehInfo->GetHandlerOffset()); + if(ehInfo->GetHandlerLength() != (DWORD) -1) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), " %s IL_%04x",KEYWORD("to"),ehInfo->GetHandlerOffset()+ehInfo->GetHandlerLength()); + + printLine(GUICookie, szString); + + if(g_fShowBytes) + DumpHexEHInfo(ehInfo, GUICookie); + /* + if(ehInfo->GetFlags() & ERR_OUT_OF_CODE) + { + sprintf(szString,"%s// WARNING: Boundary outside the method code",g_szAsmCodeIndent); + printLine(GUICookie,szString); + } + */ +} +void dumpEHInfo(IMDInternalImport *pImport, void *GUICookie) +{ + //char szString[4096]; + + if(! g_ehCount) return; + sprintf_s(szString, SZSTRING_SIZE, "%s// Exception count %d", g_szAsmCodeIndent, g_ehCount); + //sprintf_s(szString, SZSTRING_SIZE, "%s// %d irregular exception clauses", g_szAsmCodeIndent, g_ehCount); + printLine(GUICookie, COMMENT(szString)); + + for (unsigned i = 0; i < g_ehCount; i++) + { + DasmExceptionInfoClause* ehInfo = &g_ehInfo[i]; + dumpOneEHInfo(ehInfo,pImport,GUICookie); + } +} + +static int __cdecl cmpLineCode(const void *p1, const void *p2) +{ int ret = (((LineCodeDescr*)p1)->PC - ((LineCodeDescr*)p2)->PC); + if(ret==0) + { + ret= (((LineCodeDescr*)p1)->Line - ((LineCodeDescr*)p2)->Line); + if(ret==0) ret= (((LineCodeDescr*)p1)->Column - ((LineCodeDescr*)p2)->Column); + } + return ret; +} + +static int __cdecl cmpLexScope(const void *p1, const void *p2) +{ + LexScope* pls1 = (LexScope*)p1; + LexScope* pls2 = (LexScope*)p2; + int d; + if((d = pls1->dwStart - pls2->dwStart)) return d; + return (pls2->dwEnd - pls1->dwEnd); +} + +char* DumpDataPtr(__inout __nullterminated char* buffer, DWORD ptr, DWORD size) +{ + // check if ptr really points to some data in one of sections + IMAGE_SECTION_HEADER *pSecHdr = NULL; + DWORD i; + DWORD dwNumberOfSections; + if(g_pPELoader->IsPE32()) + { + pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders32()); + dwNumberOfSections = VAL16(g_pPELoader->ntHeaders32()->FileHeader.NumberOfSections); + } + else + { + pSecHdr = IMAGE_FIRST_SECTION(g_pPELoader->ntHeaders64()); + dwNumberOfSections = VAL16(g_pPELoader->ntHeaders64()->FileHeader.NumberOfSections); + } + + for (i=0; i < dwNumberOfSections; i++,pSecHdr++) + { + if((ptr >= VAL32(pSecHdr->VirtualAddress))&& + (ptr < VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize))) + { + if(ptr+size > VAL32(pSecHdr->VirtualAddress)+VAL32(pSecHdr->Misc.VirtualSize)) i = dwNumberOfSections; + break; + } + } + if(i < dwNumberOfSections) + { // yes, the pointer points to real data + int j; + for(j=0; (j < g_iPtrCount)&&((*g_pPtrTags)[j] != (__int32)ptr); j++); + if(j == g_iPtrCount) + { + if (g_pPtrSize == NULL) + { + g_pPtrSize = new DynamicArray<DWORD>; + } + if (g_pPtrTags == NULL) + { + g_pPtrTags = new DynamicArray<__int32>; + } + + (*g_pPtrSize)[g_iPtrCount] = size; + (*g_pPtrTags)[g_iPtrCount++] = ptr; + } + else if((*g_pPtrSize)[j] < size) (*g_pPtrSize)[j] = size; + const char* szTls = "D_"; + if(strcmp((const char*)(pSecHdr->Name),".tls") == 0) szTls = "T_"; + else if(strcmp((const char*)(pSecHdr->Name),".text") == 0) szTls = "I_"; + buffer+=sprintf_s(buffer,SZSTRING_REMAINING_SIZE(buffer), "%s%8.8X",szTls,ptr); + } //else print as hex + else + { + buffer+=sprintf_s(buffer,SZSTRING_REMAINING_SIZE(buffer),ERRORMSG("0x%8.8X /* WARNING: rogue pointer! (size 0x%8.8X) */"),ptr,size); + } + return buffer; +} + +void DumpLocals(IMDInternalImport *pImport,COR_ILMETHOD_DECODER *pMethod, __in __nullterminated char* szVarPrefix, void* GUICookie) +{ + if (pMethod->GetLocalVarSigTok()) + { + DWORD cbSigLen; + PCCOR_SIGNATURE pComSig; + CQuickBytes qbMemberSig; + size_t dwL; + + + if (FAILED(pImport->GetSigFromToken(pMethod->GetLocalVarSigTok(), &cbSigLen, &pComSig))) + { + printLine(GUICookie, "Invalid record"); + return; + } + + _ASSERTE(*pComSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); + + appendStr(&qbMemberSig, g_szAsmCodeIndent); + appendStr(&qbMemberSig, KEYWORD(".locals ")); + if(g_fDumpTokens) + { + char sz[32]; + sprintf_s(sz,32,"/*%08X*/ ",pMethod->GetLocalVarSigTok()); + appendStr(&qbMemberSig,COMMENT(sz)); + } + if(pMethod->GetFlags() & CorILMethod_InitLocals) appendStr(&qbMemberSig, KEYWORD("init ")); + dwL = qbMemberSig.Size(); + + char* pszTailSig = (char *) PrettyPrintSig(pComSig, cbSigLen, 0, &qbMemberSig, pImport,szVarPrefix); + if(strlen(pszTailSig) < dwL+3) return; + + { + ULONG32 i,j,k,indent = (ULONG32)strlen(g_szAsmCodeIndent)+9; // indent+.locals ( + char chAfterComma; + char *pComma = pszTailSig, *pch; + while((pComma = strchr(pComma,','))) + { + for(pch = pszTailSig, i=0, j=0, k=0; pch < pComma; pch++) + { + if(*pch == '\'') j=1-j; + else if(j==0) + { + if(*pch == '[') i++; + else if(*pch == ']') i--; + else if(strncmp(pch,LTN(),strlen(LTN()))==0) k++; + else if(strncmp(pch,GTN(),strlen(GTN()))==0) k--; + } + } + pComma++; + if((i==0)&&(k==0)&&(j==0)) // no brackets or all opened/closed + { + chAfterComma = *pComma; + *pComma = 0; + printLine(GUICookie,pszTailSig); + *pComma = chAfterComma; + for(i=0; i<indent; i++) pszTailSig[i] = ' '; + strcpy_s(&pszTailSig[indent],strlen(pComma)+1,pComma); + pComma = pszTailSig; + } + } + } + printLine(GUICookie, pszTailSig); + } +} +void LoadScope(ISymUnmanagedScope *pIScope, + DynamicArray<LexScope> *pdaScope, + ULONG *pulScopes) +{ + ULONG32 ulVars; + ULONG32 ulStart; + ULONG32 ulEnd; + ISymUnmanagedScope** ppChildScope = new ISymUnmanagedScope*[4096]; + ULONG32 ulChildren; + unsigned i; + + if(SUCCEEDED(pIScope->GetLocalCount(&ulVars)) && ulVars) + { + if(SUCCEEDED(pIScope->GetStartOffset(&ulStart)) && + SUCCEEDED(pIScope->GetEndOffset(&ulEnd))) + { + (*pdaScope)[*pulScopes].dwStart = ulStart; + (*pdaScope)[*pulScopes].dwEnd = ulEnd; + (*pdaScope)[*pulScopes].dwZOrder = 0; + (*pdaScope)[*pulScopes].pISymScope = pIScope; + pIScope->AddRef(); + (*pulScopes)++; + } + } + if(SUCCEEDED(pIScope->GetChildren(4096,&ulChildren,ppChildScope))) + { + for(i = 0; i < ulChildren; i++) + { + if(ppChildScope[i]) { + LoadScope(ppChildScope[i],pdaScope,pulScopes); + ppChildScope[i]->Release(); + } + } + } + VDELETE(ppChildScope); + +} +//#define SHOW_LEXICAL_SCOPES +void OpenScope(ISymUnmanagedScope *pIScope, + __inout_ecount(ulLocals) ParamDescriptor *pLV, + ULONG ulLocals) +{ + ULONG32 dummy; + ULONG32 ulVars; + ULONG32 ulSlot; + ISymUnmanagedVariable** pVars = NULL; + + if(FAILED(pIScope->GetLocalCount(&ulVars))) return; + + ULONG32 ulNameLen; +#ifdef SHOW_LEXICAL_SCOPES + for(unsigned jj = 0; jj < ulLocals; jj++) pLV[jj].attr = 0xFFFFFFFF; +#endif + if(ulVars) + { + pVars = new ISymUnmanagedVariable*[ulVars+4]; + memset(pVars,0,sizeof(PVOID)*(ulVars+4)); + + if(SUCCEEDED(pIScope->GetLocals(ulVars+4,&dummy,pVars))) + { + WCHAR* wzName = wzUniBuf; + char* szName = NULL; + for(ULONG ilv = 0; ilv < ulVars; ilv++) + { + if(pVars[ilv]) + { + // get the local var slot number and make sure that it's in bounds: + if(SUCCEEDED(pVars[ilv]->GetAddressField1(&ulSlot)) && ulSlot < ulLocals) + { + if(SUCCEEDED(pVars[ilv]->GetName(UNIBUF_SIZE/2,&ulNameLen,wzName))) + { + szName = UnicodeToUtf(wzName); +#ifndef SHOW_LEXICAL_SCOPES + for(ULONG32 j=0; j<ulLocals; j++) + { + if(j == ulSlot) continue; + if((pLV[ulSlot].name!=NULL)&&(!strcmp(szName,pLV[j].name))) + { + sprintf_s(szName,UNIBUF_SIZE/2,"V_%d",ulSlot); + break; + } + } +#endif + if (!*szName) + sprintf_s(szName,UNIBUF_SIZE/2,"V_%d",ulSlot); + ulNameLen = (ULONG32) strlen(szName); + if((pLV[ulSlot].name==NULL)||(ulNameLen > (ULONG32)strlen(pLV[ulSlot].name))) + { + VDELETE(pLV[ulSlot].name); + pLV[ulSlot].name = new char[ulNameLen+1]; + } + if(pLV[ulSlot].name != NULL) + strcpy_s(pLV[ulSlot].name,ulNameLen+1,szName); + } + pLV[ulSlot].attr = ulSlot; + } + pVars[ilv]->Release(); + } + } + } + VDELETE(pVars); + } +} + +char* DumpUnicodeString(void* GUICookie, + __inout __nullterminated char* szString, + __in_ecount(cbString) WCHAR* pszString, + ULONG cbString, + bool SwapString ) +{ + unsigned i,L; + char* szStr=NULL, *szRet = NULL; +#if defined(ALIGN_ACCESS) || BIGENDIAN + WCHAR* pszStringCopy = NULL; + // Make a copy if the string is unaligned or we have to modify it + if (cbString > 0) + { +#if !BIGENDIAN + if((size_t)pszString & (sizeof(WCHAR)-1)) +#endif + { + L = (cbString+1)*sizeof(WCHAR); + pszStringCopy = new WCHAR[cbString+1]; + memcpy(pszStringCopy, pszString, L); + pszString=pszStringCopy; + } + } +#endif + +#if BIGENDIAN + if (SwapString) + SwapStringLength(pszString, cbString); +#endif + + // first, check for embedded zeros: + for(i=0; i < cbString; i++) + { + if(pszString[i] == 0) goto DumpAsByteArray; + } + szStr = new char[cbString*3 + 5]; + memset(szStr,0,cbString*3 + 5); + + WszWideCharToMultiByte(CP_UTF8,0,pszString,cbString,&szStr[0],cbString*3,NULL,NULL); + L = (unsigned)strlen(szStr); + + szStr[L] = 0; + for(i=0; i < L; i++) + { + if((!isprint(((BYTE)(szStr[i]))))&&(szStr[i]!='\t')&&(szStr[i]!='\n')&&(szStr[i]!='\r')) break; + } + + if(i == L) + { + szRet = DumpQString(GUICookie,szStr,g_szAsmCodeIndent, 50); + } + else + { +DumpAsByteArray: + strcat_s(szString,SZSTRING_SIZE,KEYWORD("bytearray")); + strcat_s(szString,SZSTRING_SIZE," ("); + +#if BIGENDIAN + SwapStringLength(pszString, cbString); +#endif + DumpByteArray(szString,(BYTE*)pszString,cbString*sizeof(WCHAR),GUICookie); + szRet = &szString[strlen(szString)]; + } + if(szStr) VDELETE(szStr); +#if defined(ALIGN_ACCESS) || BIGENDIAN + if(pszStringCopy) VDELETE(pszStringCopy); +#endif + return szRet; +} + +// helper to avoid mixing of SEH and stack objects with destructors +BOOL SourceLinesHelper(void *GUICookie, LineCodeDescr* pLCD, __out_ecount(nSize) WCHAR* pFileName, UINT nSize) +{ + _ASSERTE(nSize > 0); + memset(pFileName, 0, nSize * sizeof(WCHAR)); + + if(pLCD->FileToken == 0) + { + return FALSE; + } + + struct Param + { + void *GUICookie; + LineCodeDescr* pLCD; + WCHAR* pFileName; + UINT nSize; + BOOL fRet; + } param; + param.GUICookie = GUICookie; + param.pLCD = pLCD; + param.pFileName = pFileName; + param.nSize = nSize; + param.fRet = FALSE; + + PAL_TRY(Param *, pParam, ¶m) { + GUID guidLang={0},guidLangVendor={0},guidDoc={0}; + WCHAR wzLang[64],wzVendor[64],wzDoc[64]; + ULONG32 k; + if(pParam->pLCD->FileToken != ulWasFileToken) + { + ((ISymUnmanagedDocument*)(pParam->pLCD->FileToken))->GetLanguage(&guidLang); + ((ISymUnmanagedDocument*)(pParam->pLCD->FileToken))->GetLanguageVendor(&guidLangVendor); + ((ISymUnmanagedDocument*)(pParam->pLCD->FileToken))->GetDocumentType(&guidDoc); + if(memcmp(&guidLang,&guidWasLang,sizeof(GUID)) + ||memcmp(&guidLangVendor,&guidWasLangVendor,sizeof(GUID)) + ||memcmp(&guidDoc,&guidWasDoc,sizeof(GUID))) + { + GuidToLPWSTR(guidLang,wzLang,64); + GuidToLPWSTR(guidLangVendor,wzVendor,64); + GuidToLPWSTR(guidDoc,wzDoc,64); + sprintf_s(szString,SZSTRING_SIZE,"%s%s '%ls', '%ls', '%ls'", g_szAsmCodeIndent,KEYWORD(".language"), + wzLang,wzVendor,wzDoc); + printLine(pParam->GUICookie,szString); + memcpy(&guidWasLang,&guidLang,sizeof(GUID)); + memcpy(&guidWasLangVendor,&guidLangVendor,sizeof(GUID)); + memcpy(&guidWasDoc,&guidDoc,sizeof(GUID)); + } + + /* + BOOL fHasEmbeddedSource=FALSE; + ((ISymUnmanagedDocument*)(pParam->pLCD->FileToken))->HasEmbeddedSource(&fHasEmbeddedSource); + sprintf(szString,"%s// PDB has %sembedded source",g_szAsmCodeIndent, + fHasEmbeddedSource ? "" : "no "); + printLine(pParam->GUICookie,szString); + */ + } + ((ISymUnmanagedDocument*)(pParam->pLCD->FileToken))->GetURL(pParam->nSize,&k,pParam->pFileName); + ulWasFileToken = pParam->pLCD->FileToken; + pParam->fRet = TRUE; + } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_ERRORREOPENINGFILE),pLCD->FileToken); + printError(GUICookie, szString); + } + WIN_PAL_ENDTRY + + return param.fRet; +} + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +BOOL Disassemble(IMDInternalImport *pImport, BYTE *ILHeader, void *GUICookie, mdToken FuncToken, ParamDescriptor* pszArgname, ULONG ulArgs) +{ + HRESULT hr; + DWORD PC; + BOOL fNeedNewLine = FALSE; + //char szString[4096]; + char* szptr; + BYTE* pCode = NULL; + BOOL fTryInCode; + + COR_ILMETHOD_DECODER method((COR_ILMETHOD*) ILHeader); + + pCode = const_cast<BYTE*>(method.Code); + + sprintf_s(szString,SZSTRING_SIZE, RstrUTF(IDS_E_CODESIZE),g_szAsmCodeIndent, method.GetCodeSize(), method.GetCodeSize()); + printLine(GUICookie, szString); + + if(method.GetCodeSize() == 0) return TRUE; + + sprintf_s(szString,SZSTRING_SIZE, "%s%s %d",g_szAsmCodeIndent, KEYWORD(".maxstack"),method.GetMaxStack()); + printLine(GUICookie, szString); + + //------------ Source lines display --------------------------------- + ULONG32 ulLines =0; + LineCodeDescr* LineCode = NULL; + BOOL fShowSource = FALSE; + BOOL fInsertSourceLines = FALSE; + LineCodeDescr* pLCD = NULL; + ParamDescriptor* pszLVname = NULL; + ULONG ulVars=0; + char szVarPrefix[64]; + // scope handling: + DynamicArray<LexScope> daScope; + ULONG ulScopes=0; + DWORD dwScopeZOrder = 0; + ISymUnmanagedScope* pRootScope = NULL; + ISymUnmanagedMethod* pSymMethod = NULL; + char szFileName[2048]; + ISymUnmanagedDocument* pMethodDoc[2] = {NULL,NULL}; + ULONG32 ulMethodLine[2]; + ULONG32 ulMethodCol[2]; + BOOL fHasRangeInfo = FALSE; + + strcpy_s(szVarPrefix,64,"V0"); + if(g_pSymReader) + { + g_pSymReader->GetMethod(FuncToken,&pSymMethod); + if(g_fShowSource || g_fInsertSourceLines) + { + if(pSymMethod) + { + unsigned ulActualLines=0; // VS compilers produce "Hidden" line numbers, don't count them + if(FAILED(pSymMethod->GetSourceStartEnd(pMethodDoc,ulMethodLine,ulMethodCol,&fHasRangeInfo))) + { + fHasRangeInfo = FALSE; + } + pSymMethod->GetSequencePointCount(&ulLines); + if (ulLines != 0) + { + LineCode = new LineCodeDescr[ulLines+2]; + memset(LineCode, 0, sizeof(LineCodeDescr) * (ulLines + 2)); + } + if(ulLines != 0 && LineCode != NULL) + { + pLCD = &LineCode[0]; + if(fHasRangeInfo) + { + //printLine(GUICookie,"// Has source range info"); + pLCD->Line = ulMethodLine[0]; + pLCD->Column = ulMethodCol[0]; + pLCD->PC = 0; + pLCD->FileToken = (ULONG_PTR)pMethodDoc[0]; + ulActualLines++; + pLCD++; + } + if(ulLines) + { + ULONG32 *offsets=new ULONG32[ulLines], *lines=new ULONG32[ulLines], *columns=new ULONG32[ulLines]; + ULONG32 *endlines=new ULONG32[ulLines], *endcolumns=new ULONG32[ulLines]; + ISymUnmanagedDocument** docs = (ISymUnmanagedDocument**)(new PVOID[ulLines]); + ULONG32 actualCount; + pSymMethod->GetSequencePoints(ulLines,&actualCount, offsets,docs,lines,columns, endlines, endcolumns); + for(ULONG i = 0; i < ulLines; i++) + { + pLCD->Line = lines[i]; + pLCD->Column = columns[i]; + pLCD->LineEnd = endlines[i]; + pLCD->ColumnEnd = endcolumns[i]; + pLCD->PC = offsets[i]; + pLCD->FileToken = (ULONG_PTR)docs[i]; + ulActualLines++; + pLCD++; + } + VDELETE(offsets); + VDELETE(lines); + VDELETE(columns); + VDELETE(endlines); + VDELETE(endcolumns); + VDELETE(docs); + } // end if(ulLines) + if(fHasRangeInfo) + { + pLCD->Line = ulMethodLine[1]; + pLCD->Column = ulMethodCol[1]; + pLCD->PC = method.GetCodeSize(); + pLCD->FileToken = (ULONG_PTR)pMethodDoc[1]; + ulActualLines++; + pLCD++; + } + + ulLines = ulActualLines; + qsort(LineCode,ulLines,sizeof(LineCodeDescr),cmpLineCode); + fShowSource = g_fShowSource; + fInsertSourceLines = g_fInsertSourceLines; + pLCD = &LineCode[0]; + } // end if(LineCode) + } //end if (pSymMethod) + }//end if(g_fShowSource) + if (method.GetLocalVarSigTok()) + { + // first, get the real number of local vars from signature + DWORD cbSigLen; + PCCOR_SIGNATURE pComSig; + mdSignature mdLocalVarSigTok = method.GetLocalVarSigTok(); + if ((TypeFromToken(mdLocalVarSigTok) != mdtSignature) || + (!pImport->IsValidToken(mdLocalVarSigTok)) || (RidFromToken(mdLocalVarSigTok) == 0)) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_BOGUSLVSIG),mdLocalVarSigTok); + printError(GUICookie,szString); + return FALSE; + } + if (FAILED(pImport->GetSigFromToken(mdLocalVarSigTok, &cbSigLen, &pComSig))) + { + sprintf_s(szString, SZSTRING_SIZE, RstrUTF(IDS_E_INVALIDRECORD), mdLocalVarSigTok); + printError(GUICookie, szString); + return FALSE; + } + _ASSERTE(*pComSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); + pComSig++; + + ULONG ulVarsInSig = CorSigUncompressData(pComSig); + if(pSymMethod) pSymMethod->GetRootScope(&pRootScope); + else pRootScope = NULL; + + if(pRootScope) + { + ulVars = ulVarsInSig; + } + else ulVars = 0; + if(ulVars) + { + ULONG ilvs; + pszLVname = new ParamDescriptor[ulVars]; + memset(pszLVname,0,ulVars*sizeof(ParamDescriptor)); + for(ilvs = 0; ilvs < ulVars; ilvs++) + { + pszLVname[ilvs].name = new char[16]; + sprintf_s(pszLVname[ilvs].name,16,"V_%d",ilvs); + pszLVname[ilvs].attr = ilvs; + } + LoadScope(pRootScope,&daScope,&ulScopes); + qsort(&daScope[0],ulScopes,sizeof(LexScope),cmpLexScope); + OpenScope(pRootScope,pszLVname,ulVars); +#ifdef _WIN64 + sprintf_s(szVarPrefix,64,"@%I64d0",(size_t)pszLVname); +#else + sprintf_s(szVarPrefix,64,"@%d0",(size_t)pszLVname); +#endif //_WIN64 + +#ifndef SHOW_LEXICAL_SCOPES + for(unsigned jjj = 0; jjj < ulScopes; jjj++) + { + OpenScope(daScope[jjj].pISymScope,pszLVname,ulVars); + daScope[jjj].pISymScope->Release(); + } + ulScopes = 0; +#endif + } //end if(ulLVScount) + if(pRootScope) pRootScope->Release(); + } //end if (method.LocalVarSigTok) + } //end if(g_pDebugImport) + //------------------------------------------------------------------- + g_tkRefUser = FuncToken; + DumpLocals(pImport,&method, szVarPrefix, GUICookie); + g_tkRefUser = 0; + +#if defined(_DEBUG) + const BYTE* curFormat = pCode; + #pragma warning(disable : 4640) + static ILFormatter ilFormatter; + static OutString formatOut; + static OutString line; + #pragma warning(default : 4640) + + if (g_fPrettyPrint) { + extern IMetaDataImport2* g_pPubImport; + ilFormatter.init(g_pPubImport, method.Code, &method.Code[method.CodeSize], method.MaxStack, method.EH); + } +#endif + + PC = 0; + fTryInCode = enumEHInfo(method.EH, pImport, method.GetCodeSize()); + DasmExceptionInfoClause* ehInfoToPutNext = NULL; + if(g_Mode & MODE_GUI) + { // in GUI, reset everything for each method + ulWasFileToken = 0xFFFFFFFF; + memset(&guidWasLang,0,sizeof(GUID)); + memset(&guidWasLangVendor,0,sizeof(GUID)); + memset(&guidWasDoc,0,sizeof(GUID)); + memset(wzWasFileName,0,sizeof(wzWasFileName)); + ulWasLine = 0; + } + while (PC < method.GetCodeSize()) + { + DWORD Len; + DWORD i,ii; + OPCODE instr; + char sz[1024]; + + instr = DecodeOpcode(&pCode[PC], &Len); + if (instr == CEE_COUNT) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_INSTRDECOD), pCode[PC],PC,PC); + printError(GUICookie, szString); + /* + while (PC < method.CodeSize) + { + printf("%02x\n", pCode[PC]); + PC++; + } + */ + return FALSE; + } + + if (fNeedNewLine) + { + fNeedNewLine = FALSE; + if (!(g_Mode & MODE_GUI)) + printLine(GUICookie,""); + } + + if(fShowSource || fInsertSourceLines) + { + while(PC == pLCD->PC) + { + bIsNewFile = FALSE; + if((pLCD->FileToken != ulWasFileToken) || (pLCD->Line < ulWasLine)) + { + WCHAR wzFileName[2048]; + SourceLinesHelper(GUICookie, pLCD, wzFileName, 2048); + bIsNewFile = (wcscmp(wzFileName,wzWasFileName)!=0); + if(bIsNewFile||(pLCD->Line < ulWasLine)) + { + wcscpy_s(wzWasFileName,2048,wzFileName); + memset(szFileName,0,2048); + WszWideCharToMultiByte(CP_UTF8,0,wzFileName,-1,szFileName,2048,NULL,NULL); + if(fShowSource) + { + if(pFile) fclose(pFile); + pFile = NULL; + if(fopen_s(&pFile,szFileName,"rt") != 0) + { + char* pch = strrchr(szFileName,'\\'); + if(pch == NULL) pch = strrchr(szFileName,':'); + pFile = NULL; + if(pch) fopen_s(&pFile,pch+1,"rt"); + } + if(bIsNewFile) + { + sprintf_s(szString,SZSTRING_SIZE,"// Source File '%s' %s",szFileName,(pFile ? "" : "not found")); + printLine(GUICookie, COMMENT(szString)); + } + ulWasLine = 0; + } + } + } + if(fInsertSourceLines) + { + if(bIsNewFile) + { + const char* pszFN = ProperName(szFileName); + sprintf_s(szString,SZSTRING_SIZE,(*pszFN == '\'' ? "%s%s %d,%d : %d,%d %s" + : "%s%s %d,%d : %d,%d '%s'"), + g_szAsmCodeIndent,KEYWORD(".line"),pLCD->Line,pLCD->LineEnd, + pLCD->Column,pLCD->ColumnEnd,pszFN); + } + else + sprintf_s(szString,SZSTRING_SIZE,"%s%s %d,%d : %d,%d ''",g_szAsmCodeIndent,KEYWORD(".line"), + pLCD->Line,pLCD->LineEnd,pLCD->Column,pLCD->ColumnEnd); + + printLine(GUICookie,szString); + } + + ULONG k= pLCD->Line; + if(pFile) + { + for(k = ulWasLine; k < pLCD->Line; k++) + { + if(NULL==fgets(sz,1024,pFile)) { k--; break;} + if((ulWasLine != 0)||(k == (pLCD->Line-1))) + { + while((sz[strlen(sz)-1]=='\n') || (sz[strlen(sz)-1]=='\r')) sz[strlen(sz)-1]=0; + sprintf_s(szString,SZSTRING_SIZE,"//%6.6d: %s",k+1,sz); + printLine(GUICookie, COMMENT(szString)); + } + } + ulWasLine = k; + } + if(pLCD < &LineCode[ulLines-1]) pLCD++; + else { fShowSource = FALSE; break; } + } + } + if(fTryInCode) + { + g_tkRefUser = FuncToken; + // dumpOneEHInfo(ehInfoToPutNext,pImport,GUICookie); //doesn't do anything if ehInfoToPutNext == NULL + g_tkRefUser = 0; + ehInfoToPutNext = NULL; + + for(ii = g_ehCount; ii > 0; ii--) + { + i = g_ehCount - ii; + DWORD theEnd = g_ehInfo[i].GetHandlerOffset()+g_ehInfo[i].GetHandlerLength(); + if(g_ehInfo[i].GetFlags() & PUT_INTO_CODE) + { + if(PC == theEnd) + { + // reduce indent, close } + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,UNSCOPE(),COMMENT("// end handler")); + printLine(GUICookie,szString); + if(g_fShowBytes) + DumpHexEHInfo(&g_ehInfo[i], GUICookie); + g_ehInfo[i].SetTryOffset(0xFF000000); + g_ehInfo[i].SetHandlerOffset(0xFF000000); + } + } + else + { + DWORD theTryEnd = g_ehInfo[i].GetTryOffset()+g_ehInfo[i].GetTryLength(); + if(theTryEnd > theEnd) theEnd = theTryEnd; // try block after the handler + if(PC == theEnd) // If we've already found the first, don't skip to the next one + ehInfoToPutNext = &g_ehInfo[i]; + } + } + + for(i = 0; i < g_ehCount; i++) + { + if(g_ehInfo[i].GetFlags() & PUT_INTO_CODE) + { + if(g_ehInfo[i].GetFlags() & NEW_TRY_BLOCK) + { + if(PC == g_ehInfo[i].GetTryOffset()+g_ehInfo[i].GetTryLength()) + { + // reduce indent, close } + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,UNSCOPE(),COMMENT("// end .try")); + printLine(GUICookie,szString); + } + if(PC == g_ehInfo[i].GetTryOffset()) + { + // Put try, {, increase indent + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,KEYWORD(".try")); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + } + } + + DWORD dwFlags = g_ehInfo[i].GetFlags(); + + if ((dwFlags & COR_ILEXCEPTION_CLAUSE_FILTER) && PC == g_ehInfo[i].GetFilterOffset()) + { + // Dump filter clause, {, increase indent + sprintf_s(szString,SZSTRING_SIZE, "%s%s", g_szAsmCodeIndent, KEYWORD("filter")); + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + } + + if(PC == g_ehInfo[i].GetHandlerOffset()) + { + if (dwFlags & COR_ILEXCEPTION_CLAUSE_FILTER) + { + // reduce indent, close } (of the filter block) + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE, "%s%s %s", g_szAsmCodeIndent, UNSCOPE(), COMMENT("// end filter")); + + // Dump handler clause, {, increase indent + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE, "%s%s %s", g_szAsmCodeIndent, SCOPE(), COMMENT("// handler")); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + } + else + { + // Dump catch or finally clause, {, increase indent + if (dwFlags & COR_ILEXCEPTION_CLAUSE_FAULT) + sprintf_s(szString,SZSTRING_SIZE, "%s%s", g_szAsmCodeIndent, KEYWORD("fault")); + else if (dwFlags & COR_ILEXCEPTION_CLAUSE_FINALLY || IsNilToken(g_ehInfo[i].GetClassToken())) + sprintf_s(szString,SZSTRING_SIZE, "%s%s", g_szAsmCodeIndent,KEYWORD("finally")); + else + { + CQuickBytes out; + sprintf_s(szString,SZSTRING_SIZE, "%s%s %s ",g_szAsmCodeIndent,KEYWORD("catch"), + PrettyPrintClass(&out, g_ehInfo[i].GetClassToken(), pImport)); + REGISTER_REF(FuncToken,g_ehInfo[i].GetClassToken()); + } + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + } + } + } // end if(g_ehInfo[i].Flags & PUT_INTO_CODE) + } // end for(i<g_ehCount) + } // end if(fTryInCode) + //----------------- lexical scope handling ----------------------------- + if(ulScopes) // non-zero only if local var info present + { + for(i=0; i < ulScopes; i++) + { + if(daScope[i].pISymScope != pRootScope) + { + if(daScope[i].IsOpen()) + { + if(!daScope[i].Covers(PC)) + { + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); + daScope[i].dwZOrder = 0; + dwScopeZOrder--; + if(PC > daScope[i].dwEnd) + { + sprintf_s(szString,SZSTRING_SIZE,COMMENT("%s// PDB ERROR: scope end (0x%8.8X) is not opcode-aligned"), + g_szAsmCodeIndent,daScope[i].dwEnd); + printLine(GUICookie,szString); + } + } // end if(!daScope[i].Covers(PC)) + } + else // i.e., if scope is not open + { + if(daScope[i].Covers(PC)) + { + if(g_fShowBytes) + sprintf_s(szString,SZSTRING_SIZE,"%s%s // 0x%8.8X - 0x%8.8X",g_szAsmCodeIndent,SCOPE(), + daScope[i].dwStart,daScope[i].dwEnd); + else + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + OpenScope(daScope[i].pISymScope,pszLVname,ulVars); + DumpLocals(pImport,&method, szVarPrefix, GUICookie); + dwScopeZOrder++; + daScope[i].dwZOrder = dwScopeZOrder; + if(PC > daScope[i].dwStart) + { + sprintf_s(szString,SZSTRING_SIZE,COMMENT("%s// PDB ERROR: scope start (0x%8.8X) is not opcode-aligned"), + g_szAsmCodeIndent,daScope[i].dwStart); + printLine(GUICookie,szString); + } + } // end if(daScope[i].Covers(PC)) + } // end if(daScope[i].IsOpen()) -- else + } // end if(daScope[i].pISymScope != pRootScope) + } // end for(i=0; i < ulScopes; i++) + } // end if(ulScopes) + +#if defined(_DEBUG) + if (g_fPrettyPrint && &pCode[PC] >= curFormat) { + formatOut.clear(); + curFormat = ilFormatter.formatStatement(curFormat, &formatOut); + char* ptr = const_cast<char*>(formatOut.val()); + do { + char* newLine = strchr(ptr, '\n'); + if (newLine) + *newLine++ = 0; + line.clear(); + line << COMMENT((char*)0)<<"// **** " << ptr<<COMMENT((char*)-1); + printLine(GUICookie, const_cast<char*>(line.val())); + ptr = newLine; + } while (ptr != 0 && *ptr != 0); + } +#endif + + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%sIL_%04x: ",g_szAsmCodeIndent, PC); + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s/* ",COMMENT((char*)0)); + for(i=0; i<Len; i++) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%2.2X",pCode[PC+i]); + for(; i<2; i++) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," "); // 2 is max.opcode length + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," | "); + } + + PC += Len; + Len = 0; + + const char *pszInstrName = KEYWORD(OpcodeInfo[instr].pszName); + + switch (OpcodeInfo[instr].Type) + { + DWORD tk; + DWORD tkType; + default: + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),RstrUTF(IDS_E_INSTRTYPE), + OpcodeInfo[instr].Type,instr); + printLine(GUICookie, szString); + return FALSE; + } + +#define PadTheString { if(Len < 16) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-*s", (16-Len), ""); \ + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," */%s ",COMMENT((char*)-1)); } + + case InlineNone: + { + if(g_fShowBytes) + PadTheString; + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), pszInstrName); + + switch (instr) + { + case CEE_RET: + case CEE_THROW: + fNeedNewLine = TRUE; + break; + default: + break; + } + + break; + } + + case ShortInlineI: + case ShortInlineVar: + { + unsigned char ch= pCode[PC]; + short sh = OpcodeInfo[instr].Type==ShortInlineVar ? ch : (ch > 127 ? -(256-ch) : ch); + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X ", ch); + Len += 3; + PadTheString; + } + switch(instr) + { + case CEE_LDARG_S: + case CEE_LDARGA_S: + case CEE_STARG_S: + if(g_fThisIsInstanceMethod &&(ch==0)) + { // instance methods have arg0="this", do not label it! + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %d", pszInstrName, ch); + } + else + { + if(pszArgname) + { + unsigned char ch1 = g_fThisIsInstanceMethod ? ch-1 : ch; + if(ch1 < ulArgs) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%-10s %s",pszInstrName, + ProperLocalName(pszArgname[ch1].name)); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG(RstrUTF(IDS_E_ARGINDEX)),pszInstrName, ch,ulArgs); + } + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s A_%d",pszInstrName, ch); + } + break; + + case CEE_LDLOC_S: + case CEE_LDLOCA_S: + case CEE_STLOC_S: + if(pszLVname) + { + if(ch < ulVars) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %s", pszInstrName, + ProperLocalName(pszLVname[ch].name)); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG(RstrUTF(IDS_E_LVINDEX)),pszInstrName, ch, ulVars); + } + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s V_%d",pszInstrName, ch); + break; + + default: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %d", pszInstrName,sh); + } + + PC++; + break; + } + + case InlineVar: + { + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X%2.2X ", pCode[PC], pCode[PC+1]); + Len += 5; + PadTheString; + } + + USHORT v = pCode[PC] + (pCode[PC+1] << 8); + long l = OpcodeInfo[instr].Type==InlineVar ? v : (v > 0x7FFF ? -(0x10000 - v) : v); + + switch(instr) + { + case CEE_LDARGA: + case CEE_LDARG: + case CEE_STARG: + if(g_fThisIsInstanceMethod &&(v==0)) + { // instance methods have arg0="this", do not label it! + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %d", pszInstrName, v); + } + else + { + if(pszArgname) + { + USHORT v1 = g_fThisIsInstanceMethod ? v-1 : v; + if(v1 < ulArgs) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%-10s %s",pszInstrName, + ProperLocalName(pszArgname[v1].name)); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG(RstrUTF(IDS_E_ARGINDEX)),pszInstrName, v,ulArgs); + } + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s A_%d",pszInstrName, v); + } + break; + + case CEE_LDLOCA: + case CEE_LDLOC: + case CEE_STLOC: + if(pszLVname) + { + if(v < ulVars) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %s", pszInstrName, + ProperLocalName(pszLVname[v].name)); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG(RstrUTF(IDS_E_LVINDEX)),pszInstrName, v,ulVars); + } + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s V_%d",pszInstrName, v); + break; + + default: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %d", pszInstrName, l); + break; + } + PC += 2; + break; + } + + case InlineI: + case InlineRVA: + { + DWORD v = pCode[PC] + (pCode[PC+1] << 8) + (pCode[PC+2] << 16) + (pCode[PC+3] << 24); + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X%2.2X%2.2X%2.2X ", pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + Len += 9; + PadTheString; + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s 0x%x", pszInstrName, v); + PC += 4; + break; + } + + case InlineI8: + { + __int64 v = (__int64) pCode[PC] + + (((__int64) pCode[PC+1]) << 8) + + (((__int64) pCode[PC+2]) << 16) + + (((__int64) pCode[PC+3]) << 24) + + (((__int64) pCode[PC+4]) << 32) + + (((__int64) pCode[PC+5]) << 40) + + (((__int64) pCode[PC+6]) << 48) + + (((__int64) pCode[PC+7]) << 56); + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), + "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", + pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3], + pCode[PC+4], pCode[PC+5], pCode[PC+6], pCode[PC+7]); + Len += 8*2; + PadTheString; + } + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s 0x%I64x", pszInstrName, v); + PC += 8; + break; + } + + case ShortInlineR: + { + __int32 v = (__int32) pCode[PC] + + (((__int32) pCode[PC+1]) << 8) + + (((__int32) pCode[PC+2]) << 16) + + (((__int32) pCode[PC+3]) << 24); + + float f = (float&)v; + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X%2.2X%2.2X%2.2X ", pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + Len += 9; + PadTheString; + } + + char szf[32]; + if(f==0.0) + strcpy_s(szf,32,((v>>24)==0)? "0.0" : "-0.0"); + else + _gcvt_s(szf,32,(double)f, 8); + float fd = (float)atof(szf); + // Must compare as underlying bytes, not floating point otherwise optmizier will + // try to enregister and comapre 80-bit precision number with 32-bit precision number!!!! + if(((__int32&)fd == v)&&(strchr(szf,'#') == NULL)) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %s", pszInstrName, szf); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s (%2.2X %2.2X %2.2X %2.2X)", + pszInstrName, pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + PC += 4; + break; + } + + case InlineR: + { + __int64 v = (__int64) pCode[PC] + + (((__int64) pCode[PC+1]) << 8) + + (((__int64) pCode[PC+2]) << 16) + + (((__int64) pCode[PC+3]) << 24) + + (((__int64) pCode[PC+4]) << 32) + + (((__int64) pCode[PC+5]) << 40) + + (((__int64) pCode[PC+6]) << 48) + + (((__int64) pCode[PC+7]) << 56); + + double d = (double&)v; + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), + "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", + pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3], + pCode[PC+4], pCode[PC+5], pCode[PC+6], pCode[PC+7]); + Len += 8*2; + PadTheString; + } + char szf[32],*pch; + if(d==0.0) + strcpy_s(szf,32,((v>>56)==0)? "0.0" : "-0.0"); + else + _gcvt_s(szf,32,d, 17); + double df = strtod(szf, &pch); //atof(szf); + // Must compare as underlying bytes, not floating point otherwise optmizier will + // try to enregister and comapre 80-bit precision number with 64-bit precision number!!!! + if(((__int64&)df == v)&&(strchr(szf,'#') == NULL)) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %s", pszInstrName, szf); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s (%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X)", + pszInstrName, pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3], + pCode[PC+4], pCode[PC+5], pCode[PC+6], pCode[PC+7]); + PC += 8; + break; + } + + case ShortInlineBrTarget: + { + char offset = (char) pCode[PC]; + long dest = (PC + 1) + (long) offset; + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X ", pCode[PC]); + Len += 3; + PadTheString; + } + PC++; + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s IL_%04x", pszInstrName, dest); + + fNeedNewLine = TRUE; + break; + } + + case InlineBrTarget: + { + long offset = pCode[PC] + (pCode[PC+1] << 8) + (pCode[PC+2] << 16) + (pCode[PC+3] << 24); + long dest = (PC + 4) + (long) offset; + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X%2.2X%2.2X%2.2X ", pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + Len += 9; + PadTheString; + } + PC += 4; + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s IL_%04x", pszInstrName, dest); + + fNeedNewLine = TRUE; + break; + } + + case InlineSwitch: + { + DWORD cases = pCode[PC] + (pCode[PC+1] << 8) + (pCode[PC+2] << 16) + (pCode[PC+3] << 24); + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X%2.2X%2.2X%2.2X ", pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + Len += 9; + PadTheString; + } + if(cases) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s ( ", pszInstrName); + else szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s ( )", pszInstrName); + printLine(GUICookie, szString); + PC += 4; + DWORD PC_nextInstr = PC + 4 * cases; + for (i = 0; i < cases; i++) + { + long offset = pCode[PC] + (pCode[PC+1] << 8) + (pCode[PC+2] << 16) + (pCode[PC+3] << 24); + long dest = PC_nextInstr + (long) offset; + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s ",g_szAsmCodeIndent); //indent+label + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"/* | %2.2X%2.2X%2.2X%2.2X ", // comment + pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + Len = 9; + PadTheString; + } + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," IL_%04x%s", dest,(i == cases-1)? ")" : ","); + PC += 4; + printLine(GUICookie, szString); + } + continue; + } + + case InlinePhi: + { + DWORD cases = pCode[PC]; + unsigned short *pus; + DWORD i; + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X", cases); + Len += 2; + for(i=0; i < cases*2; i++) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X", pCode[PC+1+i]); + Len += 2; + } + PadTheString; + } + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s", pszInstrName); + for(i=0, pus=(unsigned short *)(&pCode[PC+1]); i < cases; i++,pus++) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr)," %d",*pus); + } + PC += 2 * cases + 1; + break; + } + + case InlineString: + case InlineField: + case InlineType: + case InlineTok: + case InlineMethod: + { + tk = pCode[PC] + (pCode[PC+1] << 8) + (pCode[PC+2] << 16) + (pCode[PC+3] << 24); + tkType = TypeFromToken(tk); + + // Backwards compatible ldstr instruction. + if (instr == CEE_LDSTR && TypeFromToken(tk) != mdtString) + { + WCHAR *v1 = L""; + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X%2.2X%2.2X%2.2X ", + pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + Len += 9; + PadTheString; + } + + if(!g_pPELoader->getVAforRVA(tk, (void**) &v1)) + { + char szStr[256]; + sprintf_s(szStr,256,RstrUTF(IDS_E_SECTHEADER),tk); + printLine(GUICookie,szStr); + } + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s ", pszInstrName); + ConvToLiteral(szptr, v1, 0xFFFF); + PC += 4; + break; + } + + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "(%2.2X)%2.2X%2.2X%2.2X ", + pCode[PC+3], pCode[PC+2], pCode[PC+1], pCode[PC]); + Len += 11; + PadTheString; + } + PC += 4; + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s ", pszInstrName); + + if ((tk & 0xFF000000) == 0) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%#x ", tk); + break; + } + if(!pImport->IsValidToken(tk)) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),ERRORMSG(" [ERROR: INVALID TOKEN 0x%8.8X] "),tk); + break; + } + if(OpcodeInfo[instr].Type== InlineTok) + { + switch (tkType) + { + default: + break; + + case mdtMethodDef: + case mdtMethodSpec: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("method ")); + break; + + case mdtFieldDef: + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("field ")); + break; + + case mdtMemberRef: + { + PCCOR_SIGNATURE typePtr; + const char* pszMemberName; + ULONG cComSig; + + if (FAILED(pImport->GetNameAndSigOfMemberRef( + tk, + &typePtr, + &cComSig, + &pszMemberName))) + { + szptr += sprintf_s(szptr, SZSTRING_REMAINING_SIZE(szptr), "ERROR "); + break; + } + unsigned callConv = CorSigUncompressData(typePtr); + + if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD)) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("field ")); + else + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("method ")); + break; + } + } + } + PrettyPrintToken(szString, tk, pImport,GUICookie,FuncToken); //TypeDef,TypeRef,TypeSpec,MethodDef,FieldDef,MemberRef,MethodSpec,String + break; + } + + case InlineSig: + { + if(g_fShowBytes) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%2.2X%2.2X%2.2X%2.2X ", + pCode[PC], pCode[PC+1], pCode[PC+2], pCode[PC+3]); + // output the offset and the raw bytes + Len += 9; + PadTheString; + } + + // get the signature token + tk = pCode[PC] + (pCode[PC+1] << 8) + (pCode[PC+2] << 16) + (pCode[PC+3] << 24); + PC += 4; + tkType = TypeFromToken(tk); + if (tkType == mdtSignature) + { + // get the signature from the token + DWORD cbSigLen; + PCCOR_SIGNATURE pComSig; + CQuickBytes qbMemberSig; + if (FAILED(pImport->GetSigFromToken(tk, &cbSigLen, &pComSig))) + { + sprintf_s(szString, SZSTRING_SIZE, COMMENT("// ERROR: Invalid %08X record"), tk); + break; + } + + qbMemberSig.Shrink(0); + const char* pszTailSig = PrettyPrintSig(pComSig, cbSigLen, "", &qbMemberSig, pImport,NULL); + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), "%-10s %s", pszInstrName, pszTailSig); + if (g_fDumpTokens) + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(" /*%08X*/"),tk); + } + else + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), ERRORMSG(RstrUTF(IDS_E_BADTOKENTYPE)), pszInstrName, tk); + } + break; + } + } + + printLine(GUICookie, szString); + } // end while (PC < method.CodeSize) + + // We've finished looping over all the instructions, + // Close of anything that may still be open + // First, dump any remaining EH regions + if(g_ehCount) + { + g_tkRefUser = FuncToken; + DWORD i; + if(fTryInCode) + { + for (DWORD ii = g_ehCount; ii > 0; ii--) + { + i = g_ehCount - ii; + DWORD theEnd = g_ehInfo[i].GetHandlerOffset()+g_ehInfo[i].GetHandlerLength(); + if(g_ehInfo[i].GetFlags() & PUT_INTO_CODE) + { + if(PC == theEnd) + { + // reduce indent, close } + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,UNSCOPE(),COMMENT("// end handler")); + printLine(GUICookie,szString); + if(g_fShowBytes) + DumpHexEHInfo(&g_ehInfo[i], GUICookie); + g_ehInfo[i].SetTryOffset(0xFF000000); + g_ehInfo[i].SetHandlerOffset(0xFF000000); + } + } + } + //dumpOneEHInfo(ehInfoToPutNext,pImport,GUICookie); //doesn't do anything if ehInfoToPutNext == NULL + } + bool fMoreToDisplay = false; + for (i = 0; i < g_ehCount && !fMoreToDisplay; i++) + fMoreToDisplay = !(g_ehInfo[i].GetTryOffset() == 0xFF000000 && g_ehInfo[i].GetHandlerOffset() == 0xFF000000); + if (fMoreToDisplay) + { + sprintf_s(szString,SZSTRING_SIZE,"%sIL_%04x: ",g_szAsmCodeIndent, method.GetCodeSize()); //add dummy label + printLine(GUICookie, szString); + dumpEHInfo(pImport,GUICookie); + } + g_tkRefUser = 0; + } + //----------------- lexical scope handling ----------------------------- + if(ulScopes) // non-zero only if local var info present + { + for(unsigned i=0; i < ulScopes; i++) + { + if(daScope[i].pISymScope != pRootScope) + { + if((daScope[i].dwZOrder > 0)&&(PC >= daScope[i].dwEnd)) + { + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); + daScope[i].dwZOrder = 0; + dwScopeZOrder--; + if(PC > daScope[i].dwEnd) + { + sprintf_s(szString,SZSTRING_SIZE,COMMENT("%s// PDB ERROR: scope end (0x%8.8X) is not opcode-aligned"), + g_szAsmCodeIndent,daScope[i].dwEnd); + printLine(GUICookie,szString); + } + } + } + daScope[i].pISymScope->Release(); + } + } + if(dwScopeZOrder != 0) + { + sprintf_s(szString,SZSTRING_SIZE,COMMENT("%s// PDB ERROR: %d unclosed lexical scopes, forcing closure."), + g_szAsmCodeIndent,dwScopeZOrder); + printLine(GUICookie,szString); + for(DWORD i=0; i < dwScopeZOrder; i++) + { + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); + } + } + if(pSymMethod) pSymMethod->Release(); + if(LineCode) VDELETE(LineCode); + if(pszLVname) + { + for(ULONG i = 0; i < ulVars; i++) SDELETE(pszLVname[i].name); + VDELETE(pszLVname); + } +// dumpEHInfo(pImport, GUICookie); + + return TRUE; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +void SplitSignatureByCommas(__inout __nullterminated char* szString, + __inout __nullterminated char* pszTailSig, + mdToken tk, + size_t indent, + void* GUICookie) +{ + char chAfterComma; + char *pComma, *pch; + size_t i,j,k,l; + if(indent < strlen(pszTailSig)) + { + pComma = pszTailSig+indent; + while((pComma = strchr(pComma,',')) != NULL) + { + for(pch = pszTailSig, i=0,j=0,k=0,l=0; pch < pComma; pch++) + { + if(*pch == '\'') j=1-j; + else if(j==0) + { + if(*pch == '[') i++; + else if(*pch == ']') i--; + else if(*pch == '(') k++; + else if(*pch == ')') k--; + else if(strncmp(pch,LTN(),strlen(LTN()))==0) l++; + else if(strncmp(pch,GTN(),strlen(GTN()))==0) l--; + } + } + pComma++; + if((i==0)&&(j==0)&&(k<=1)&&(l==0)) // no brackets or all opened/closed + { + chAfterComma = *pComma; + *pComma = 0; + printLine(GUICookie,pszTailSig); + *pComma = chAfterComma; + strcpy_s(pszTailSig,strlen(g_szAsmCodeIndent)+1,g_szAsmCodeIndent); + for(i=(ULONG32)strlen(g_szAsmCodeIndent); i<indent; i++) pszTailSig[i] = ' '; + strcpy_s(&pszTailSig[indent],strlen(pComma)+1,pComma); + pComma = pszTailSig; + } + } + } + pch = szString; + pch+=sprintf_s(pch,SZSTRING_SIZE,"%s",pszTailSig); + if(g_fDumpTokens) + pch+=sprintf_s(pch,SZSTRING_REMAINING_SIZE(pch),COMMENT(" /* %08X */"),tk); +} + +//#define TOKEN_SIG +#ifdef TOKEN_SIG +struct TokenSig +{ + size_t indent; + char* str; + TokenSig() { indent = 0; str = NULL; }; + ~TokenSig() { if(str) VDELETE(str); }; +}; +struct TokenSigArray +{ + TokenSig* ptsArray; + ULONG ulCount; + mdToken tkType; + TokenSigArray(mdToken tk, IMDInternalImport *pImport) + { + HENUMInternal hEnum; + pImport->EnumAllInit(tk,&hEnum); + ulCount=pImport->EnumGetCount(&hEnum)+1; + pImport->EnumClose(&hEnum); + ptsArray = new TokenSig[ulCount]; + tkType = tk; + }; + ~TokenSigArray() + { + VDELETE(ptsArray); + } +}; + +TokenSigArray *TSA_TD = NULL; +TokenSigArray *TSA_TR = NULL; +TokenSigArray *TSA_TS = NULL; +TokenSigArray *TSA_AR = NULL; +TokenSigArray *TSA_MR = NULL; +TokenSigArray *TSA_FD = NULL; +TokenSigArray *TSA_MD = NULL; +TokenSigArray *TSA_ME = NULL; +TokenSigArray *TSA_MS = NULL; + +#endif +void TokenSigInit(IMDInternalImport *pImport) +{ +#ifdef TOKEN_SIG + TSA_TD = new TokenSigArray(mdtTypeDef,pImport); + TSA_TR = new TokenSigArray(mdtTypeRef,pImport); + TSA_TS = new TokenSigArray(mdtTypeSpec,pImport); + TSA_AR = new TokenSigArray(mdtAssemblyRef,pImport); + TSA_MR = new TokenSigArray(mdtModuleRef,pImport); + TSA_FD = new TokenSigArray(mdtFieldDef,pImport); + TSA_MD = new TokenSigArray(mdtMethodDef,pImport); + TSA_ME = new TokenSigArray(mdtMemberRef,pImport); + TSA_MS = new TokenSigArray(mdtMethodSpec,pImport); +#endif +} +void TokenSigDelete() +{ +#ifdef TOKEN_SIG + SDELETE(TSA_TD); + SDELETE(TSA_TR); + SDELETE(TSA_TS); + SDELETE(TSA_AR); + SDELETE(TSA_MR); + SDELETE(TSA_FD); + SDELETE(TSA_MD); + SDELETE(TSA_ME); + SDELETE(TSA_MS); +#endif +} + +// Returns S_OK as TRUE or S_FALSE as FALSE or error code +HRESULT +IsGenericInst(mdToken tk, IMDInternalImport *pImport) +{ + HRESULT hr; + if (TypeFromToken(tk) == mdtTypeSpec) + { + if (pImport->IsValidToken(tk)) + { + ULONG cSig; + PCCOR_SIGNATURE sig; + IfFailRet(pImport->GetSigFromToken(tk, &cSig, &sig)); + + PCCOR_SIGNATURE sigEnd = sig + cSig; + while (sig < sigEnd) + { + unsigned t = (unsigned)*sig; + switch (t) + { + case ELEMENT_TYPE_PTR: + case ELEMENT_TYPE_SZARRAY: + case ELEMENT_TYPE_ARRAY: + case ELEMENT_TYPE_BYREF: + sig++; + break; + default: + { + if (*sig == ELEMENT_TYPE_GENERICINST) + { + return S_OK; + } + else + { + return S_FALSE; + } + } + } + } + } + } + return S_FALSE; +} + +char* PrettyPrintMemberRef(__inout __nullterminated char* szString, mdToken tk, PCCOR_SIGNATURE pInstSig, ULONG cInstSig, + IMDInternalImport *pImport, void* GUICookie, size_t* pIndent, + CQuickBytes *pqbMemberSig) +{ + HRESULT hr; + mdTypeRef cr; + const char * pszMemberName; + char* curPos; + char* pszTailSig; + char* pszOffset; + PCCOR_SIGNATURE pComSig; + ULONG cComSig; + size_t L, indent; + mdToken tkVarOwner = g_tkVarOwner; + DWORD dwAttrs=0xFFFFFFFF; // used only if Parent==MethodDef + mdToken tkMethodDef = 0; // used only if Parent==MethodDef + + L = strlen(szString); + + if (FAILED(pImport->GetNameAndSigOfMemberRef( + tk, + &pComSig, + &cComSig, + &pszMemberName))) + { + pComSig = NULL; + cComSig = 0; + pszMemberName = "Invalid MemberRef record"; + } + MAKE_NAME_IF_NONE(pszMemberName,tk); + + curPos = &szString[L+1]; + *curPos = 0; + if (FAILED(pImport->GetParentOfMemberRef(tk, &cr))) + { + curPos += sprintf_s(curPos, SZSTRING_REMAINING_SIZE(curPos), "Invalid MemberRef %08X record", tk); + cr = mdTypeRefNil; + } + if (TypeFromToken(cr) == mdtMethodDef) //get the parent's parent + { + if (FAILED(pImport->GetMethodDefProps(cr, &dwAttrs))) + { + curPos += sprintf_s(curPos, SZSTRING_REMAINING_SIZE(curPos), "Invalid MethodDef %08X record", cr); + } + tkMethodDef = cr; + + mdTypeRef cr1; + if(FAILED(pImport->GetParentToken(cr,&cr1))) cr1 = mdTypeRefNil; + cr = cr1; + } + pqbMemberSig->Shrink(0); + if (RidFromToken(cr)&&(cr != 0x02000001)) + { + const char* pszClass = PrettyPrintClass(pqbMemberSig,cr,pImport); + sprintf_s(curPos,SZSTRING_REMAINING_SIZE(curPos),"%s::",pszClass); + pqbMemberSig->Shrink(0); + + hr = IsGenericInst(cr,pImport); + if (FAILED(hr)) + { + sprintf_s(curPos, SZSTRING_REMAINING_SIZE(curPos), "Invalid token %08X record", cr); + } + if (hr == S_OK) + { + g_tkVarOwner = 0; + } + } + { + char* curPos1 = &curPos[strlen(curPos)]; + if (IsMdPrivateScope(dwAttrs)) + { + sprintf_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),"%s$PST%08X",pszMemberName,tkMethodDef); + } + else + { + strcpy_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),pszMemberName); + } + if (tkMethodDef != 0) + { + strcpy_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),JUMPPT(ProperName(curPos1),tkMethodDef)); + } + else + { + strcpy_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),ProperName(curPos1)); + } + } + + appendStr(pqbMemberSig, szString); + if (pInstSig != NULL) + { + CQuickBytes qbInstSig; + qbInstSig.Shrink(0); + PrettyPrintSig(pInstSig, cInstSig, curPos, &qbInstSig, pImport, NULL); + strcat_s(curPos,SZSTRING_REMAINING_SIZE(curPos), (char*) qbInstSig.Ptr()); + } + pszTailSig = (char*)PrettyPrintSig(pComSig, cComSig, curPos, pqbMemberSig, pImport,NULL,(pInstSig==NULL)); + pszOffset = strstr(pszTailSig,curPos); + indent = pszOffset - pszTailSig + strlen(curPos) + 1; + if(pIndent) *pIndent = indent; + g_tkVarOwner = tkVarOwner; + return pszTailSig; +} + +char* PrettyPrintMethodDef(__inout __nullterminated char* szString, mdToken tk, PCCOR_SIGNATURE pInstSig, ULONG cInstSig, + IMDInternalImport *pImport,void* GUICookie, size_t* pIndent, + CQuickBytes *pqbMemberSig) +{ + HRESULT hr; + mdTypeRef cr; + const char * pszMemberName; + char* curPos; + char* pszTailSig; + char* pszOffset; + DWORD dwAttrs; + PCCOR_SIGNATURE pComSig; + ULONG cComSig; + size_t L, indent; + mdToken tkVarOwner = g_tkVarOwner; + + L = strlen(szString); + if (FAILED(pImport->GetNameOfMethodDef(tk, &pszMemberName))) + { + pszMemberName = "Invalid MethodDef record"; + } + MAKE_NAME_IF_NONE(pszMemberName,tk); + if (FAILED(pImport->GetMethodDefProps(tk, &dwAttrs))) + { + sprintf_s(szString, SZSTRING_SIZE, "Invalid MethodDef %08X record", tk); + return szString; + } + + if (FAILED(pImport->GetSigOfMethodDef(tk, &cComSig, &pComSig))) + { + cComSig = 0; + pComSig = NULL; + } + + hr = pImport->GetParentToken( + tk, + &cr + ); + if (FAILED(hr)) + { + strcat_s(szString, SZSTRING_SIZE, "??"); + return szString; + } + // use the tail as a buffer + curPos = &szString[L+1]; + *curPos=0; + pqbMemberSig->Shrink(0); + if(RidFromToken(cr)&&(cr != 0x02000001)) + { + const char* pszClass = PrettyPrintClass(pqbMemberSig,cr,pImport); + sprintf_s(curPos,SZSTRING_REMAINING_SIZE(curPos),"%s::",pszClass); + pqbMemberSig->Shrink(0); + + hr = IsGenericInst(cr,pImport); + if (FAILED(hr)) + { + sprintf_s(curPos, SZSTRING_REMAINING_SIZE(curPos), "/*Invalid token %08X record*/", cr); + } + if (hr == S_OK) + { + g_tkVarOwner = 0; + } + } + { + char* curPos1 = &curPos[strlen(curPos)]; + if(IsMdPrivateScope(dwAttrs)) + sprintf_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),"%s$PST%08X",pszMemberName,tk); + else + strcpy_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),pszMemberName); + strcpy_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),JUMPPT(ProperName(curPos1),tk)); + } + appendStr(pqbMemberSig, szString); + if (pInstSig) + { + CQuickBytes qbInstSig; + qbInstSig.Shrink(0); + pszTailSig = (char*)PrettyPrintSig(pInstSig, cInstSig, curPos, &qbInstSig, pImport, NULL); + strcat_s(curPos,SZSTRING_REMAINING_SIZE(curPos), (char*) qbInstSig.Ptr()); + } + + pszTailSig = (char*)PrettyPrintSig(pComSig, cComSig, curPos, pqbMemberSig, pImport, NULL, (pInstSig == NULL)); + pszOffset = strstr(pszTailSig,curPos); + indent = pszOffset - pszTailSig + strlen(curPos) + 1; + if(pIndent) *pIndent = indent; + g_tkVarOwner = tkVarOwner; + return pszTailSig; +} + +void PrettyPrintTokenWithSplit(__inout __nullterminated char* szString, mdToken tk, IMDInternalImport *pImport, void* GUICookie) +{ + CQuickBytes qbMemberSig; + char* pszTailSig = NULL; + size_t L, indent; + + L = strlen(szString); + +#ifdef TOKEN_SIG + TokenSig* SigToken=NULL; + switch(TypeFromToken(tk)) + { + case mdtMethodDef: SigToken = TSA_MD->ptsArray; break; + case mdtMethodSpec: SigToken = TSA_MS->ptsArray; break; + case mdtMemberRef: SigToken = TSA_ME->ptsArray; break; + default: return; // other token types aren't served + } + if(SigToken[RidFromToken(tk)].str) + { + qbMemberSig.Shrink(0); + appendStr(&qbMemberSig, szString); + appendStr(&qbMemberSig, SigToken[RidFromToken(tk)].str); + pszTailSig = asString(&qbMemberSig); + indent = SigToken[RidFromToken(tk)].indent + L; + } + else +#endif + { + switch(TypeFromToken(tk)) + { + case mdtMethodDef: + pszTailSig = PrettyPrintMethodDef(szString,tk,NULL,0,pImport,GUICookie,&indent,&qbMemberSig); + break; + case mdtMemberRef: + pszTailSig = PrettyPrintMemberRef(szString,tk,NULL,0,pImport,GUICookie,&indent,&qbMemberSig); + break; + case mdtMethodSpec: + { + mdToken meth=0; + PCCOR_SIGNATURE pSig=NULL; + ULONG cSig=0; + mdToken tkMVarOwner = g_tkMVarOwner; + g_tkMVarOwner = 0; + if (FAILED(pImport->GetMethodSpecProps(tk, &meth, &pSig, &cSig))) + { + return; + } + pszTailSig = (TypeFromToken(meth) == mdtMethodDef) ? + PrettyPrintMethodDef(szString,meth,pSig,cSig,pImport,GUICookie,&indent,&qbMemberSig) : + PrettyPrintMemberRef(szString,meth,pSig,cSig,pImport,GUICookie,&indent,&qbMemberSig); + g_tkMVarOwner = tkMVarOwner; + } + break; + default: + return; + } + +#ifdef TOKEN_SIG + SigToken[RidFromToken(tk)].str = new char[strlen(pszTailSig+L)+1]; + if(SigToken[RidFromToken(tk)].str) + { + strcpy_s(SigToken[RidFromToken(tk)].str,strlen(pszTailSig+L)+1,pszTailSig+L); + SigToken[RidFromToken(tk)].indent = indent - L; + } +#endif + } + SplitSignatureByCommas(szString,pszTailSig,tk,indent,GUICookie); +} + +void PrettyPrintToken(__inout __nullterminated char* szString, mdToken tk, IMDInternalImport *pImport,void* GUICookie, mdToken FuncToken) +{ +#ifdef TOKEN_SIG + + TokenSig* SigToken=NULL; + +#endif + char *szptr = &szString[strlen(szString)]; + if(!pImport->IsValidToken(tk)) + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), ERRORMSG("<invalid token 0x%8.8x>"), tk); + return; + } + mdToken tkType = TypeFromToken(tk); + + DWORD ix; + for(ix = 0; ix < g_NumTypedefs; ix++) + { + if((*g_typedefs)[ix].tkTypeSpec == tk) break; + } + if(ix < g_NumTypedefs) + { + REGISTER_REF(FuncToken,tk); + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr),JUMPPT(ProperName((*g_typedefs)[ix].szName),(*g_typedefs)[ix].tkSelf)); + return; + } + +#ifdef TOKEN_SIG + switch (tkType) + { + case mdtTypeDef: SigToken = TSA_TD->ptsArray; break; + case mdtTypeRef: SigToken = TSA_TR->ptsArray; break; + case mdtTypeSpec: SigToken = TSA_TS->ptsArray; break; + case mdtAssemblyRef: SigToken = TSA_AR->ptsArray; break; + case mdtModuleRef: SigToken = TSA_MR->ptsArray; break; + case mdtFieldDef: SigToken = TSA_FD->ptsArray; break; + default: SigToken = NULL; break; + } + + if(SigToken && SigToken[RidFromToken(tk)].str) + { + REGISTER_REF(FuncToken,tk); + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr),SigToken[RidFromToken(tk)].str); + return; + } +#endif + CQuickBytes out; + char* pszForTokenSig = NULL; + + switch (tkType) + { + default: + { + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr), ERRORMSG("<unknown token type 0x%02x>"), (BYTE) (tkType >> 24)); + pszForTokenSig = NULL; + break; + } + + case mdtTypeDef: + case mdtTypeRef: + case mdtTypeSpec: + case mdtAssemblyRef: + case mdtAssembly: + case mdtModuleRef: + case mdtModule: + { + REGISTER_REF(FuncToken,tk); + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr), PrettyPrintClass(&out, tk, pImport)); + pszForTokenSig = szptr; + break; + } + + case mdtMethodDef: + case mdtMemberRef: + PrettyPrintTokenWithSplit(szString,tk,pImport,GUICookie); + REGISTER_REF(FuncToken,tk); + break; + + case mdtMethodSpec: + { + mdToken meth=0; + PCCOR_SIGNATURE pSig; + ULONG cSig; + if (FAILED(pImport->GetMethodSpecProps(tk, &meth, &pSig, &cSig))) + { + meth = mdTokenNil; + } + //g_tkMVarOwner = 0; + PrettyPrintTokenWithSplit(szString,tk,pImport,GUICookie); + REGISTER_REF(FuncToken,meth); + break; + } + + case mdtFieldDef: + { + HRESULT hr; + mdTypeRef cr=0; + const char * pszMemberName; + CQuickBytes qbMemberSig; + DWORD dwAttrs; + + PCCOR_SIGNATURE pComSig; + ULONG cComSig; + + REGISTER_REF(FuncToken,tk); + if (FAILED(pImport->GetNameOfFieldDef(tk, &pszMemberName))) + { + strcat_s(szString, SZSTRING_SIZE, "??"); + break; + } + MAKE_NAME_IF_NONE(pszMemberName,tk); + if (FAILED(pImport->GetFieldDefProps(tk, &dwAttrs))) + { + sprintf_s(szString, SZSTRING_SIZE, "Invalid FieldDef %08X record", tk); + break; + } + + if (FAILED(pImport->GetSigOfFieldDef(tk, &cComSig, &pComSig)) || + FAILED(pImport->GetParentToken(tk, &cr))) + { + sprintf_s(szString, SZSTRING_SIZE, "Invalid FieldDef %08X record", tk); + break; + } + + // use the tail as a buffer + char* curPos = &szString[strlen(szString)+1]; + *curPos = 0; + if((cr != 0x02000001) && RidFromToken(cr)) + { + const char* pszClass = PrettyPrintClass(&out, cr, pImport); + REGISTER_REF(FuncToken,cr); + sprintf_s(curPos,SZSTRING_REMAINING_SIZE(curPos),"%s::", pszClass); + } + char* curPos1 = &curPos[strlen(curPos)]; + if(IsFdPrivateScope(dwAttrs)) + sprintf_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),"%s$PST%08X",pszMemberName,tk); + else + strcpy_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),pszMemberName); + strcpy_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),JUMPPT(ProperName(curPos1),tk)); + qbMemberSig.Shrink(0); + strcpy_s(curPos-1,SZSTRING_REMAINING_SIZE(curPos), PrettyPrintSig(pComSig, cComSig, curPos, &qbMemberSig, pImport,NULL)); + curPos1 = &curPos[strlen(curPos)]; + if(g_fDumpTokens) + sprintf_s(curPos1,SZSTRING_REMAINING_SIZE(curPos1),COMMENT(" /* %08X */"),tk); + pszForTokenSig = szptr; + break; + } + + case mdtString: + { + const WCHAR *pszString = NULL; + ULONG cbString = 0; + if (pImport->IsValidToken(tk)) + { + if (FAILED(pImport->GetUserString(tk, &cbString, NULL, &pszString))) + { + pszString = NULL; + } + } + if (pszString != NULL) + { + DumpUnicodeString(GUICookie,szString,(WCHAR *)pszString,cbString, true); + } + else + { + sprintf_s(szString,SZSTRING_SIZE,ERRORMSG("INVALID TOKEN: 0x%8.8X"),tk); + } + if (g_fDumpTokens) + sprintf_s(&szString[strlen(szString)],SZSTRING_SIZE-strlen(szString),COMMENT(" /* %08X */"),tk); + break; + } + } //end switch(TypeFromToken(tk)) + +#ifdef TOKEN_SIG + if(SigToken && pszForTokenSig) + { + unsigned N = RidFromToken(tk); + SigToken[N].str = new char[strlen(pszForTokenSig)+1]; + if(SigToken[N].str) + strcpy_s(SigToken[N].str,strlen(pszForTokenSig)+1,pszForTokenSig); + } +#endif +} + +/* not const char * const because it gets sorted at runtime; arguably a bad time to sort it. */ +static const char* keyword[] = { +#define OPDEF(c,s,pop,push,args,type,l,s1,s2,ctrl) s, +#define OPALIAS(alias_c, s, c) s, +#include "opcode.def" +#undef OPALIAS +#undef OPDEF +#define KYWD(name, sym, val) name, +#include "il_kywd.h" +#undef KYWD +}; +static bool KywdNotSorted = TRUE; +static char* szAllowedSymbols = "#_@$."; +static char DisallowedStarting[256]; +static char DisallowedCont[256]; + +struct Indx +{ + void* table[128]; + Indx() { memset(table,0,sizeof(table)); }; + ~Indx() + { + for(int i = 1; i < 128; i++) delete ((Indx*)(table[i])); + }; + void IndexString(__in __nullterminated const char* psz, __out const char** pkywd) + { + int i = (int) *psz; + if(i == 0) + table[0] = pkywd; + else + { + _ASSERTE((i > 0)&&(i <= 127)); + Indx* pInd = (Indx*)(table[i]); + if(pInd == NULL) + { + pInd = new Indx; + _ASSERTE(pInd); + table[i] = pInd; + } + pInd->IndexString(psz+1,pkywd); + } + } + const char** FindString(__in __nullterminated const char* psz) + { + if(*psz == 0) + return (const char**)(table[0]); + if(*psz > 0) + { + Indx* pInd = (Indx*)(table[(unsigned char)*psz]); + return (pInd == NULL) ? NULL : pInd->FindString(psz+1); + } + return NULL; + } +}; + +/********************************************************************************/ +/* looks up the keyword 'name' Returns FALSE on failure */ +bool IsNameToQuote(const char *name) +{ + BYTE* p; + BOOL bStarting; + static Indx* indx; + + if (indx==NULL) + indx = new Indx(); + + if((name==NULL)||(*name==0)) return TRUE; + + if(g_fQuoteAllNames) + return ((strcmp(name,COR_CTOR_METHOD_NAME)!=0) && (strcmp(name,COR_CCTOR_METHOD_NAME)!=0)); + + if(KywdNotSorted) + { + int j; + const char** const low = keyword; + const char** const high = &keyword[sizeof(keyword) / sizeof(*keyword)]; + const char** mid; + // name must start with alpha or one of allowed chars: #_$@. + memset(DisallowedStarting,1,256); + for(p = (BYTE*)szAllowedSymbols; *p; DisallowedStarting[*p]=0,p++); + for(j='a'; j<= 'z'; DisallowedStarting[j]=0,j++); + for(j='A'; j<= 'Z'; DisallowedStarting[j]=0,j++); + // name must continue with the same chars, plus digits, and ? instead of # + memcpy(DisallowedCont,DisallowedStarting,256); + for(j='0'; j<= '9'; DisallowedCont[j]=0,j++); + DisallowedCont[(unsigned char)'#'] = 1; + DisallowedCont[(unsigned char)'?'] = 0; + DisallowedCont[(unsigned char)'`'] = 0; + // Sort the keywords for fast lookup + for(mid = low; mid < high; mid++) + { + indx->IndexString(*mid,mid); + } + KywdNotSorted = FALSE; + } + //first, check for forbidden characters + for(p = (BYTE*)name, bStarting = TRUE; *p; p++) + { + if(bStarting) + { + if(DisallowedStarting[*p]) return TRUE; + } + else + { + if(DisallowedCont[*p]) return TRUE; + } + bStarting = (*p == '.'); + if(bStarting && (*(p+1) == '.')) return TRUE; + } + + //second, check for matching keywords (remember: .ctor and .cctor are names AND keywords) + if(indx->FindString((char*)name)) + { + return ((strcmp(name,COR_CTOR_METHOD_NAME)!=0) && (strcmp(name,COR_CCTOR_METHOD_NAME)!=0)); + } + //third, check if the name starts or ends with dot (.ctor and .cctor are out of the way) + return ((*name == '.') || (name[strlen(name)-1] == '.')); +} + +/* Returns true if this name requires a single quote to be properly displayed as a local */ +bool IsLocalToQuote(const char *name) +{ + // Anything that would otherwise require a quote gets a quote + if (IsNameToQuote(name)) + return true; + // No such thing as an empty name that doesn't require quoting (handled in IsNameToQuote) + _ASSERTE(*name); + // return true if there's a '.' anywhere in the name, after position 1 + return !!strchr(name + 1, '.'); +} + +/********************************************************************/ +/* + * This is currently unused, with all calls to it commented out. In + * the event that those calls return, add this function back. +static char* ConvNumericEscape(char* retBuff, unsigned val) { + _ASSERTE(val < 256); + + // print as octal + *retBuff++ = '\\'; + *retBuff++ = (val >> 6) + '0'; + *retBuff++ = ((val >> 3) & 7) + '0'; + *retBuff++ = (val & 7) + '0'; + return(retBuff); +} + */ + +/********************************************************************/ +/* returns the quoted version of a string (including the quotes) */ + +static BOOL ConvToLiteral(__inout __nullterminated char* retBuff, const WCHAR* str, int cbString) +{ + BOOL ret = TRUE; + char* was_retBuff = retBuff; + + *retBuff++ = '"'; + + for(int tally=0; (tally < cbString)&&ret; tally++) + { + if (*str > 255) + { + //retBuff = ConvNumericEscape(retBuff, *str >> 8); + //retBuff = ConvNumericEscape(retBuff, *str & 0xFF); + ret = FALSE; + } + else if(!isprint(*str)) + { + if (*str == '\n') + { + *retBuff++ = '\\'; + *retBuff++ = 'n'; + } + else + //retBuff = ConvNumericEscape(retBuff, *str); + ret = FALSE; + } + else if (*str == '"') + { + *retBuff++ = '\\'; + *retBuff++ = '"'; + } + else if (*str == '\\') + { + *retBuff++ = '\\'; + *retBuff++ = '\\'; + } + else if (*str == '\t') + { + *retBuff++ = '\\'; + *retBuff++ = 't'; + } + else + *retBuff++ = (char) *str; + str++; + } + *retBuff++ = '"'; + *retBuff++ = 0; + if(!ret) *was_retBuff = 0; + return ret; +} + diff --git a/src/ildasm/dis.h b/src/ildasm/dis.h new file mode 100644 index 0000000000..1f807af0af --- /dev/null +++ b/src/ildasm/dis.h @@ -0,0 +1,154 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "formattype.h" + +#define MAX_INTERFACES_IMPLEMENTED 256 // unused +#define MAX_CLASSNAME_LENGTH 1024 // single global buffer size +#define MAX_MEMBER_LENGTH 1024 // single global buffer size +#define MAX_SIGNATURE_LENGTH 2048 // single global buffer size +#define DESCR_SIZE 8 // unused + +#define MAX_FILENAME_LENGTH 2048 //256 + +#define MODE_DUMP_ALL 0 +#define MODE_DUMP_CLASS 1 +#define MODE_DUMP_CLASS_METHOD 2 +#define MODE_DUMP_CLASS_METHOD_SIG 3 +#define MODE_GUI 4 + +BOOL Disassemble(IMDInternalImport *pImport, BYTE *pCode, void *GUICookie, mdToken FuncToken, ParamDescriptor* pszArgname, ULONG ulArgs); +BOOL Decompile(IMDInternalImport *pImport, BYTE *pCode); +OPCODE DecodeOpcode(const BYTE *pCode, DWORD *pdwLen); +struct LineCodeDescr +{ + ULONG Line; + ULONG Column; + ULONG LineEnd; + ULONG ColumnEnd; + ULONG PC; + ULONG_PTR FileToken; +}; + +void printLine(void* GUICookie, __in __nullterminated const char* string); +void printLineW(void* GUICookie, __in __nullterminated const WCHAR* string); +void printError(void* GUICookie, __in __nullterminated const char* string); + +char* AnsiToUtf(__in __nullterminated const char* sz); +char* UnicodeToAnsi(__in __nullterminated const WCHAR* wz); +char* UnicodeToUtf(__in __nullterminated const WCHAR* wz); +WCHAR* UtfToUnicode(__in __nullterminated const char* sz); +WCHAR* AnsiToUnicode(__in __nullterminated const char* sz); +void GetInputFileFullPath(); + +char* RstrUTF(unsigned id); +WCHAR* RstrW(unsigned id); +char* RstrANSI(unsigned id); + + +BOOL DumpMethod(mdToken FuncToken, const char *pszClassName, DWORD dwEntryPointToken,void *GUICookie,BOOL DumpBody); +BOOL DumpField(mdToken FuncToken, const char *pszClassName,void *GUICookie, BOOL DumpBody); +BOOL DumpEvent(mdToken FuncToken, const char *pszClassName, DWORD dwClassAttrs, void *GUICookie, BOOL DumpBody); +BOOL DumpProp(mdToken FuncToken, const char *pszClassName, DWORD dwClassAttrs, void *GUICookie, BOOL DumpBody); +void dumpEHInfo(IMDInternalImport *pImport, void *GUICookie); +BOOL DumpClass(mdTypeDef cl, DWORD dwEntryPointToken, void* GUICookie, ULONG WhatToDump); +// WhatToDump: 0-title only; 1-pack,size and custom attrs; 2-everything +BOOL GetClassLayout(mdTypeDef cl, ULONG* pulPackSize, ULONG* pulClassSize); +void DumpCustomAttribute(mdCustomAttribute tkCA, void *GUICookie, bool bWithOwner); +void DumpCustomAttributes(mdToken tkOwner, void *GUICookie); +void DumpByteArray(__inout __nullterminated char* szString, const BYTE* pBlob, ULONG ulLen, void* GUICookie); +char* DumpDataPtr(__inout __nullterminated char* buffer, DWORD ptr, DWORD size); + +void PrettyPrintToken(__inout __nullterminated char* szString, mdToken tk, IMDInternalImport *pImport,void* GUICookie,mdToken FuncToken); //TypeDef,TypeRef,TypeSpec,MethodDef,FieldDef,MemberRef,MethodSpec,String +void DumpPermissions(mdToken tkOwner, void* GUICookie); +void DumpHeader(IMAGE_COR20_HEADER *CORHeader, void* GUICookie); +void DumpHeaderDetails(IMAGE_COR20_HEADER *CORHeader, void* GUICookie); +void DumpMetaInfo(__in __nullterminated const WCHAR* pszFileName, __in_opt __nullterminated const char* pszObjFileName, void* GUICookie); +void DumpStatistics(IMAGE_COR20_HEADER *CORHeader, void* GUICookie); +BOOL DumpFile(); +void Cleanup(); +void CreateProgressBar(LONG lRange); +BOOL ProgressStep(); +void DestroyProgressBar(); +char * DumpQString(void* GUICookie, + __in __nullterminated const char* szToDump, + __in __nullterminated const char* szPrefix, + unsigned uMaxLen); +void DumpVtable(void* GUICookie); +char* DumpUnicodeString(void* GUICookie, + __inout __nullterminated char* szString, + __in_ecount(cbString) WCHAR* pszString, + ULONG cbString, + bool SwapString = false); + +void TokenSigInit(IMDInternalImport *pImport); +void TokenSigDelete(); + + +//---------------- see DMAN.CPP-------------------------------------------------- +struct LocalComTypeDescr +{ + mdExportedType tkComTypeTok; + mdTypeDef tkTypeDef; + mdToken tkImplementation; + WCHAR* wzName; + DWORD dwFlags; + LocalComTypeDescr() { wzName=NULL; }; + ~LocalComTypeDescr() { if(wzName) SDELETE(wzName); }; +}; + +struct MTokName +{ + mdFile tok; + WCHAR* name; + MTokName() { tok = 0; name = NULL; }; + ~MTokName() { if(name) SDELETE(name); }; +}; +extern BOOL g_fPrettyPrint; +extern MTokName* rExeloc; +extern ULONG nExelocs; +void DumpImplementation(mdToken tkImplementation, + DWORD dwOffset, + __inout __nullterminated char* szString, + void* GUICookie); +void DumpComType(LocalComTypeDescr* pCTD, + __inout __nullterminated char* szString, + void* GUICookie); +void DumpManifest(void* GUICookie); +void DumpTypedefs(void* GUICookie); +IMetaDataAssemblyImport* GetAssemblyImport(void* GUICookie); + +void DumpRTFPrefix(void* GUICookie, BOOL fFontDefault); +void DumpRTFPostfix(void* GUICookie); + +//------------------------------------------------------------------------------- +#define NEW_TRY_BLOCK 0x80000000 +#define PUT_INTO_CODE 0x40000000 +#define ERR_OUT_OF_CODE 0x20000000 +#define SEH_NEW_PUT_MASK (NEW_TRY_BLOCK | PUT_INTO_CODE | ERR_OUT_OF_CODE) +//------------------------------------------------------------------------------- + +// As much as 2 * SZSTRING_SIZE seems to be needed for some corner cases. ILDasm is +// unfortunately full of constants and artificial limits, and may produce invalid +// output or overrun a buffer when fed with something unusual (like a type with +// thousands of generic parameters). Fixing all such problems effectively means +// rewriting the tool from scratch. Until this happens, let's at least try to keep it +// working for reasonable input. +#define UNIBUF_SIZE 262144 +extern WCHAR wzUniBuf[]; // defined in dis.cpp + +#define SZSTRING_SIZE 131072 +extern char szString[]; // defined in dis.cpp + +char *DumpGenericPars(__inout_ecount(SZSTRING_SIZE) char* szString, + mdToken tok, + void* GUICookie=NULL, + BOOL fSplit=FALSE); + +#include "safemath.h" +#define SZSTRING_SIZE_M4 (SZSTRING_SIZE - 4) +#define CHECK_REMAINING_SIZE if(ovadd_le((size_t)szString, SZSTRING_SIZE_M4, (size_t)szptr)) break; +#define SZSTRING_REMAINING_SIZE(x) (ovadd_le((size_t)szString,SZSTRING_SIZE,(size_t)(x))?0:(SZSTRING_SIZE-((size_t)(x)-(size_t)szString))) + diff --git a/src/ildasm/dman.cpp b/src/ildasm/dman.cpp new file mode 100644 index 0000000000..917d3f467a --- /dev/null +++ b/src/ildasm/dman.cpp @@ -0,0 +1,1073 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// Assembly and Manifest Disassembler +// +#include "ildasmpch.h" + +#include "debugmacros.h" +#include "corpriv.h" +#include "dasmenum.hpp" +#include "dasmgui.h" +#include "formattype.h" +#include "dis.h" +#include "mlang.h" + +#include "ceeload.h" +#include "dynamicarray.h" +#include "resource.h" + +#include "clrinternal.h" + +extern IMAGE_COR20_HEADER * g_CORHeader; +extern IMDInternalImport* g_pImport; +extern PELoader * g_pPELoader; +extern IMetaDataImport2* g_pPubImport; +extern void * g_pMetaData; +IMetaDataAssemblyImport* g_pAssemblyImport=NULL; +extern BOOL g_fDumpAsmCode; +extern char g_szAsmCodeIndent[]; +extern char g_szOutputFile[]; +extern BOOL g_fDumpTokens; +extern DWORD g_Mode; +extern FILE* g_pFile; +extern LPCSTR* rAsmRefName; // decl. in formatType.cpp -- for AsmRef aliases +extern ULONG ulNumAsmRefs; // decl. in formatType.cpp -- for AsmRef aliases +extern unsigned g_uConsoleCP; +MTokName* rFile = NULL; +ULONG nFiles = 0; +void DumpFiles(void* GUICookie) +{ + static mdFile rFileTok[4096]; + HCORENUM hEnum=NULL; + if(rFile) { VDELETE(rFile); nFiles = 0; } + if(SUCCEEDED(g_pAssemblyImport->EnumFiles(&hEnum,rFileTok,4096,&nFiles))) + { + if(nFiles) + { + static WCHAR wzName[1024]; + ULONG ulNameLen; + const void* pHashValue; + ULONG cbHashValue; + DWORD dwFlags; + char* szptr; + rFile = new MTokName[nFiles]; + for(ULONG ix = 0; ix < nFiles; ix++) + { + pHashValue=NULL; + cbHashValue=0; + ulNameLen=0; + if(SUCCEEDED(g_pAssemblyImport->GetFileProps(rFileTok[ix],wzName,1024,&ulNameLen, + &pHashValue,&cbHashValue,&dwFlags))) + { + szptr = &szString[0]; + rFile[ix].tok = rFileTok[ix]; + rFile[ix].name = new WCHAR[ulNameLen+1]; + memcpy(rFile[ix].name,wzName,ulNameLen*sizeof(WCHAR)); + rFile[ix].name[ulNameLen] = 0; + + szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"%s%s ",g_szAsmCodeIndent,KEYWORD(".file")); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),rFileTok[ix]); + if(IsFfContainsNoMetaData(dwFlags)) szptr += sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),KEYWORD("nometadata ")); + { + int L = ulNameLen*3+3; + char* sz = new char[L]; + memset(sz,0,L); + WszWideCharToMultiByte(CP_UTF8,0,rFile[ix].name,-1,sz,L,NULL,NULL); + strcpy_s(szptr,SZSTRING_REMAINING_SIZE(szptr), ANCHORPT(ProperName(sz),rFileTok[ix])); + VDELETE(sz); + } + printLine(GUICookie,szString); + if(VAL32(IMAGE_COR20_HEADER_FIELD(*g_CORHeader, EntryPointToken)) == rFileTok[ix]) + { + printLine(GUICookie, KEYWORD(" .entrypoint")); + } + if(pHashValue && cbHashValue) + { + sprintf_s(szString,SZSTRING_SIZE," %s = (",KEYWORD(".hash")); + DumpByteArray(szString,(BYTE*)pHashValue,cbHashValue,GUICookie); + printLine(GUICookie,szString); + } + DumpCustomAttributes(rFile[ix].tok, GUICookie); + } + } + } + g_pAssemblyImport->CloseEnum(hEnum); + } + else nFiles=0; +} + +void DumpAssemblyMetaData(ASSEMBLYMETADATA* pmd, void* GUICookie) +{ + if(pmd) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s %d:%d:%d:%d",g_szAsmCodeIndent,KEYWORD(".ver"),pmd->usMajorVersion, + pmd->usMinorVersion,pmd->usBuildNumber,pmd->usRevisionNumber); + printLine(GUICookie,szString); + if(pmd->szLocale && pmd->cbLocale) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s = (",g_szAsmCodeIndent,KEYWORD(".locale")); + DumpByteArray(szString,(BYTE*)(pmd->szLocale),pmd->cbLocale*sizeof(WCHAR),GUICookie); + printLine(GUICookie,szString); + } + } +} +void DumpScope(void* GUICookie) +{ + mdModule mdm; + GUID mvid; + WCHAR scopeName[1024]; + WCHAR guidString[1024]; + memset(scopeName,0,1024*sizeof(WCHAR)); + if(SUCCEEDED(g_pPubImport->GetScopeProps( scopeName, 1024, NULL, &mvid))&& scopeName[0]) + { + { + UINT32 L = (UINT32)wcslen(scopeName)*3+3; + char* sz = new char[L]; + memset(sz,0,L); + WszWideCharToMultiByte(CP_UTF8,0,scopeName,-1,sz,L,NULL,NULL); + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,KEYWORD(".module"),ProperName(sz)); + VDELETE(sz); + } + printLine(GUICookie,szString); + StringFromGUID2(mvid, guidString, 1024); + { + UINT32 L = (UINT32)wcslen(guidString)*3+3; + char* sz = new char[L]; + memset(sz,0,L); + WszWideCharToMultiByte(CP_UTF8,0,guidString,-1,sz,L,NULL,NULL); + sprintf_s(szString,SZSTRING_SIZE,COMMENT("%s// MVID: %s"),g_szAsmCodeIndent,sz); + VDELETE(sz); + } + printLine(GUICookie,szString); + if(SUCCEEDED(g_pPubImport->GetModuleFromScope(&mdm))) + { + DumpCustomAttributes(mdm, GUICookie); + DumpPermissions(mdm, GUICookie); + } + } +} + +void DumpModuleRefs(void *GUICookie) +{ + HCORENUM hEnum=NULL; + ULONG N; + static mdToken tk[4096]; + char* szptr; + LPCSTR szName; + + g_pPubImport->EnumModuleRefs(&hEnum,tk,4096,&N); + for(ULONG i = 0; i < N; i++) + { + if(RidFromToken(tk[i])) + { + if (FAILED(g_pImport->GetModuleRefProps(tk[i],&szName))) + { + continue; + } + if (*szName != 0) // ignore the no-name ModuleRef: it's an IJW artifact + { + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,KEYWORD(".module extern"), + ANCHORPT(ProperName((char*)szName),tk[i])); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT(" /*%08X*/"),tk[i]); + printLine(GUICookie,szString); + DumpCustomAttributes(tk[i], GUICookie); + DumpPermissions(tk[i], GUICookie); + } + } + } + g_pPubImport->CloseEnum(hEnum); +} + +void DumpAssembly(void* GUICookie, BOOL fFullDump) +{ + mdAssembly tkAsm; + if(SUCCEEDED(g_pAssemblyImport->GetAssemblyFromScope(&tkAsm))&&(tkAsm != mdAssemblyNil)) + { + const void* pPublicKey; + ULONG cbPublicKey = 0; + ULONG ulHashAlgId; + WCHAR wzName[1024]; + ULONG ulNameLen=0; + ASSEMBLYMETADATA md; + WCHAR wzLocale[MAX_LOCALE_NAME]; + DWORD dwFlags; + char* szptr; + + md.szLocale = wzLocale; + md.cbLocale = MAX_LOCALE_NAME; + md.rProcessor = NULL; + md.ulProcessor = 0; + md.rOS = NULL; + md.ulOS = 0; + + if(SUCCEEDED(g_pAssemblyImport->GetAssemblyProps( // S_OK or error. + tkAsm, // [IN] The Assembly for which to get the properties. + &pPublicKey, // [OUT] Pointer to the public key. + &cbPublicKey,// [OUT] Count of bytes in the public key. + &ulHashAlgId,// [OUT] Hash Algorithm. + wzName, // [OUT] Buffer to fill with name. + 1024, // [IN] Size of buffer in wide chars. + &ulNameLen, // [OUT] Actual # of wide chars in name. + &md, // [OUT] Assembly MetaData. + &dwFlags))) // [OUT] Flags. + { + if(ulNameLen >= 1024) + { + strcpy_s(szString,SZSTRING_SIZE,RstrUTF(IDS_ASSEMNAMETOOLONG)); + printError(GUICookie,szString); + ulNameLen = 1023; + } + szptr = &szString[0]; + szptr+=sprintf_s(szptr,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".assembly")); + if(g_fDumpTokens) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),COMMENT("/*%08X*/ "),tkAsm); + + if(IsAfRetargetable(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("retargetable ")); + if(IsAfContentType_WindowsRuntime(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("windowsruntime ")); + if(IsAfPA_NoPlatform(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("noplatform ")); + if(IsAfPA_MSIL(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("cil ")); + if(IsAfPA_x86(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("x86 ")); + if(IsAfPA_IA64(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("ia64 ")); + if(IsAfPA_AMD64(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("amd64 ")); + + + wzName[ulNameLen] = 0; + { + char* sz = new char[3*ulNameLen+3]; + memset(sz,0,3*ulNameLen+3); + WszWideCharToMultiByte(CP_UTF8,0,wzName,-1,sz,3*ulNameLen+3,NULL,NULL); + strcat_s(szString,SZSTRING_SIZE,ANCHORPT(ProperName(sz),tkAsm)); + VDELETE(sz); + } + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + if(fFullDump) + { + DumpCustomAttributes(tkAsm, GUICookie); + DumpPermissions(tkAsm, GUICookie); + } + + if(fFullDump) + { + if(pPublicKey && cbPublicKey) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s = (",g_szAsmCodeIndent,KEYWORD(".publickey")); + DumpByteArray(szString,(BYTE*)pPublicKey,cbPublicKey,GUICookie); + printLine(GUICookie,szString); + } + if(ulHashAlgId) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%08X",g_szAsmCodeIndent,KEYWORD(".hash algorithm"),ulHashAlgId); + printLine(GUICookie,szString); + } + } + DumpAssemblyMetaData(&md,GUICookie); + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); + } //end if(OK(GetAssemblyProps)) + } //end if(OK(GetAssemblyFromScope)) +} + +MTokName* rAsmRef = NULL; +ULONG nAsmRefs = 0; + +void DumpAssemblyRefs(void* GUICookie) +{ + static mdAssemblyRef rAsmRefTok[4096]; + HCORENUM hEnum=NULL; + ULONG ix = 0; + if(rAsmRef) { VDELETE(rAsmRef); nAsmRefs = 0; } + if(rAsmRefName) + { + for(ix=0; ix < ulNumAsmRefs; ix++) + { + if(rAsmRefName[ix]) VDELETE(rAsmRefName[ix]); + } + VDELETE(rAsmRefName); + rAsmRefName = NULL; + ulNumAsmRefs = 0; + } + if(SUCCEEDED(g_pAssemblyImport->EnumAssemblyRefs(&hEnum,rAsmRefTok,4096,&nAsmRefs))) + { + if(nAsmRefs) + { + const void* pPublicKeyOrToken; + ULONG cbPublicKeyOrToken = 0; + const void* pHashValue; + ULONG cbHashValue; + static WCHAR wzName[1024]; + ULONG ulNameLen=0; + ASSEMBLYMETADATA md; + WCHAR wzLocale[MAX_LOCALE_NAME]; + DWORD dwFlags; + + rAsmRef = new MTokName[nAsmRefs]; + rAsmRefName = new LPCSTR[nAsmRefs]; + ulNumAsmRefs = nAsmRefs; + + for(ix = 0; ix < nAsmRefs; ix++) + { + md.szLocale = wzLocale; + md.cbLocale = MAX_LOCALE_NAME; + md.rProcessor = NULL; + md.ulProcessor = 0; + md.rOS = NULL; + md.ulOS = 0; + + ulNameLen=cbHashValue=0; + pHashValue = NULL; + if(SUCCEEDED(g_pAssemblyImport->GetAssemblyRefProps( // S_OK or error. + rAsmRefTok[ix], // [IN] The Assembly for which to get the properties. + &pPublicKeyOrToken, // [OUT] Pointer to the public key or token. + &cbPublicKeyOrToken,// [OUT] Count of bytes in the public key or token. + wzName, // [OUT] Buffer to fill with name. + 1024, // [IN] Size of buffer in wide chars. + &ulNameLen, // [OUT] Actual # of wide chars in name. + &md, // [OUT] Assembly MetaData. + &pHashValue, // [OUT] Hash blob. + &cbHashValue,// [OUT] Count of bytes in the hash blob. + &dwFlags))) // [OUT] Flags. + { + ULONG ixx; + rAsmRef[ix].tok = rAsmRefTok[ix]; + rAsmRef[ix].name = new WCHAR[ulNameLen+16]; + memcpy(rAsmRef[ix].name,wzName,ulNameLen*sizeof(WCHAR)); + rAsmRef[ix].name[ulNameLen] = 0; + if(ulNameLen >= 1024) + { + strcpy_s(szString,SZSTRING_SIZE,RstrUTF(IDS_ASMREFNAMETOOLONG)); + printError(GUICookie,szString); + wzName[1023] = 0; + } + + sprintf_s(szString,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".assembly extern")); + if(g_fDumpTokens) sprintf_s(&szString[strlen(szString)],SZSTRING_SIZE-strlen(szString),COMMENT("/*%08X*/ "),rAsmRefTok[ix]); + + if(IsAfRetargetable(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("retargetable ")); + if(IsAfContentType_WindowsRuntime(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("windowsruntime ")); + if(IsAfPA_MSIL(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("cil ")); + if(IsAfPA_x86(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("x86 ")); + if(IsAfPA_IA64(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("ia64 ")); + if(IsAfPA_AMD64(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("amd64 ")); + + { + char* sz = new char[3*ulNameLen+32]; + memset(sz,0,3*ulNameLen+3); + WszWideCharToMultiByte(CP_UTF8,0,rAsmRef[ix].name,-1,sz,3*ulNameLen+3,NULL,NULL); + // check for name duplication and introduce alias if needed + for(ixx = 0; ixx < ix; ixx++) + { + if(!wcscmp(rAsmRef[ixx].name,rAsmRef[ix].name)) break; + } + if(ixx < ix) + { + strcat_s(szString,SZSTRING_SIZE, ProperName(sz)); + char* pc=&szString[strlen(szString)]; + sprintf_s(&sz[strlen(sz)],3*ulNameLen+32-strlen(sz),"_%d",ix); + sprintf_s(pc,SZSTRING_REMAINING_SIZE(pc)," %s %s", KEYWORD("as"),ANCHORPT(ProperName(sz),rAsmRefTok[ix])); + } + else + strcat_s(szString,SZSTRING_SIZE, ANCHORPT(ProperName(sz),rAsmRefTok[ix])); + rAsmRefName[ix] = sz; + } + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + DumpCustomAttributes(rAsmRefTok[ix], GUICookie); + if(pPublicKeyOrToken && cbPublicKeyOrToken) + { + if (IsAfPublicKey(dwFlags)) + sprintf_s(szString,SZSTRING_SIZE,"%s%s = (",g_szAsmCodeIndent,KEYWORD(".publickey")); + else + sprintf_s(szString,SZSTRING_SIZE,"%s%s = (",g_szAsmCodeIndent,KEYWORD(".publickeytoken")); + DumpByteArray(szString,(BYTE*)pPublicKeyOrToken,cbPublicKeyOrToken,GUICookie); + printLine(GUICookie,szString); + } + if(pHashValue && cbHashValue) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s = (",g_szAsmCodeIndent,KEYWORD(".hash")); + DumpByteArray(szString,(BYTE*)pHashValue,cbHashValue,GUICookie); + printLine(GUICookie,szString); + } + DumpAssemblyMetaData(&md,GUICookie); + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); + } //end if(OK(GetAssemblyRefProps)) + }//end for(all assembly refs) + }//end if(nAsmRefs + g_pAssemblyImport->CloseEnum(hEnum); + }//end if OK(EnumAssemblyRefs) + else nAsmRefs=0; +} + +DynamicArray<LocalComTypeDescr*> *g_pLocalComType = NULL; +ULONG g_LocalComTypeNum = 0; + +void DumpComTypeFQN( + LocalComTypeDescr* pCTD, + __inout __nullterminated char* szName) +{ + if(TypeFromToken(pCTD->tkImplementation) == mdtExportedType) + { + ULONG i; + for(i = 0; (i < g_LocalComTypeNum) && ((*g_pLocalComType)[i]->tkComTypeTok != pCTD->tkImplementation); i++); + if(i < g_LocalComTypeNum) + { + DumpComTypeFQN((*g_pLocalComType)[i], szName); + strcat_s(szName, SZSTRING_SIZE, "/"); + } + } + + UINT32 L = (UINT32)wcslen(pCTD->wzName)*3+3; + char* sz = new char[L]; + memset(sz,0,L); + WszWideCharToMultiByte(CP_UTF8,0,pCTD->wzName,-1,sz,L,NULL,NULL); + strcat_s(szName, SZSTRING_SIZE, JUMPPT(ProperName(sz), pCTD->tkComTypeTok)); + VDELETE(sz); +} + +void DumpImplementation(mdToken tkImplementation, + DWORD dwOffset, + __inout __nullterminated char* szString, + void* GUICookie) +{ + ULONG i; + char* pc; + if(RidFromToken(tkImplementation)) + { + if(TypeFromToken(tkImplementation) == mdtFile) + { + for(i=0; (i < nFiles)&&(rFile[i].tok != tkImplementation); i++); + if(i < nFiles) + { + { + UINT32 L = (UINT32)wcslen(rFile[i].name)*3+3; + char* sz = new char[L]; + memset(sz,0,L); + WszWideCharToMultiByte(CP_UTF8,0,rFile[i].name,-1,sz,L,NULL,NULL); + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,KEYWORD(".file"), + JUMPPT(ProperName(sz),tkImplementation)); + VDELETE(sz); + } + pc=&szString[strlen(szString)]; + if(g_fDumpTokens) pc+=sprintf_s(pc,SZSTRING_REMAINING_SIZE(pc),COMMENT("/*%08X*/ "),tkImplementation); + if(dwOffset != 0xFFFFFFFF) sprintf_s(pc,SZSTRING_REMAINING_SIZE(pc)," %s 0x%08X",KEYWORD("at"),dwOffset); + printLine(GUICookie,szString); + } + } + else if(TypeFromToken(tkImplementation) == mdtAssemblyRef) + { + for(i=0; (i < nAsmRefs)&&(rAsmRef[i].tok != tkImplementation); i++); + if(i < nAsmRefs) + { + { + UINT32 L = (UINT32)wcslen(rAsmRef[i].name)*3+3; + char* sz = new char[L]; + memset(sz,0,L); + WszWideCharToMultiByte(CP_UTF8,0,rAsmRef[i].name,-1,sz,L,NULL,NULL); + sprintf_s(szString,SZSTRING_SIZE,"%s%s %s",g_szAsmCodeIndent,KEYWORD(".assembly extern"), + JUMPPT(ProperName(sz),tkImplementation)); + VDELETE(sz); + } + pc=&szString[strlen(szString)]; + if(g_fDumpTokens) sprintf_s(pc,SZSTRING_REMAINING_SIZE(pc),COMMENT(" /*%08X*/ "),tkImplementation); + printLine(GUICookie,szString); + } + } + else if(TypeFromToken(tkImplementation) == mdtExportedType) + { + // Find the type structure corresponding to this token + for(i=0; (i < g_LocalComTypeNum)&&((*g_pLocalComType)[i]->tkComTypeTok != tkImplementation); i++); + if(i < g_LocalComTypeNum) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".class extern")); + DumpComTypeFQN((*g_pLocalComType)[i], szString); + + pc=&szString[strlen(szString)]; + if(g_fDumpTokens) sprintf_s(pc,SZSTRING_REMAINING_SIZE(pc),COMMENT(" /*%08X*/ "),tkImplementation); + printLine(GUICookie,szString); + } + } + } +} + +void DumpComType(LocalComTypeDescr* pCTD, + __inout __nullterminated char* szString, + void* GUICookie) +{ + if(g_fDumpTokens) sprintf_s(&szString[strlen(szString)],SZSTRING_SIZE-strlen(szString),COMMENT("/*%08X*/ "),pCTD->tkComTypeTok); + if (IsTdPublic(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("public ")); + if (IsTdForwarder(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("forwarder ")); + if (IsTdNestedPublic(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("nested public ")); + if (IsTdNestedPrivate(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("nested private ")); + if (IsTdNestedFamily(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("nested family ")); + if (IsTdNestedAssembly(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("nested assembly ")); + if (IsTdNestedFamANDAssem(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("nested famandassem ")); + if (IsTdNestedFamORAssem(pCTD->dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("nested famorassem ")); + + char* pc=&szString[strlen(szString)]; + { + UINT32 L = (UINT32)wcslen(pCTD->wzName)*3+3; + char* sz = new char[L]; + memset(sz,0,L); + WszWideCharToMultiByte(CP_UTF8,0,pCTD->wzName,-1,sz,L,NULL,NULL); + strcpy_s(pc,SZSTRING_REMAINING_SIZE(pc),ANCHORPT(ProperName(sz),pCTD->tkComTypeTok)); + VDELETE(sz); + } + printLine(GUICookie,szString); + + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + DumpCustomAttributes(pCTD->tkComTypeTok, GUICookie); + DumpImplementation(pCTD->tkImplementation,0xFFFFFFFF,szString,GUICookie); + if(RidFromToken(pCTD->tkTypeDef)) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s 0x%08X",g_szAsmCodeIndent,KEYWORD(".class"),pCTD->tkTypeDef); + printLine(GUICookie,szString); + } + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); +} + + +void DumpComTypes(void* GUICookie) +{ + static mdExportedType rComTypeTok[4096]; + ULONG nComTypes; + HCORENUM hEnum=NULL; + + g_LocalComTypeNum = 0; + if(SUCCEEDED(g_pAssemblyImport->EnumExportedTypes(&hEnum,rComTypeTok,4096,&nComTypes))) + { + if(nComTypes) + { + static WCHAR wzName[1024]; + ULONG ulNameLen=0; + DWORD dwFlags; + mdToken tkImplementation; + mdTypeDef tkTypeDef; + + ULONG ix; + for(ix = 0; ix < nComTypes; ix++) + { + ulNameLen=0; + if(SUCCEEDED(g_pAssemblyImport->GetExportedTypeProps( // S_OK or error. + rComTypeTok[ix], // [IN] The ComType for which to get the properties. + wzName, // [OUT] Buffer to fill with name. + 1024, // [IN] Size of buffer in wide chars. + &ulNameLen, // [OUT] Actual # of wide chars in name. + &tkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ComType. + &tkTypeDef, // [OUT] TypeDef token within the file. + &dwFlags))) // [OUT] Flags. + { + LocalComTypeDescr* pCTD = new LocalComTypeDescr; + memset(pCTD,0,sizeof(LocalComTypeDescr)); + pCTD->tkComTypeTok = rComTypeTok[ix]; + pCTD->tkTypeDef = tkTypeDef; + pCTD->tkImplementation = tkImplementation; + pCTD->wzName = new WCHAR[ulNameLen+1]; + memcpy(pCTD->wzName,wzName,ulNameLen*sizeof(WCHAR)); + pCTD->wzName[ulNameLen] = 0; + pCTD->dwFlags = dwFlags; + + if (g_pLocalComType == NULL) + { + g_pLocalComType = new DynamicArray<LocalComTypeDescr*>; + } + + (*g_pLocalComType)[g_LocalComTypeNum] = pCTD; + g_LocalComTypeNum++; + } //end if(OK(GetComTypeProps)) + }//end for(all com types) + + // now, print all "external" com types + for(ix = 0; ix < nComTypes; ix++) + { + tkImplementation = (*g_pLocalComType)[ix]->tkImplementation; + // ComType of a nested class has its nester's ComType as implementation + while(TypeFromToken(tkImplementation)==mdtExportedType) + { + unsigned k; + for(k=0; k<g_LocalComTypeNum; k++) + { + if((*g_pLocalComType)[k]->tkComTypeTok == tkImplementation) + { + tkImplementation = (*g_pLocalComType)[k]->tkImplementation; + break; + } + } + if(k==g_LocalComTypeNum) break; + } + // At this moment, tkImplementation is impl.of top nester + if(RidFromToken(tkImplementation)) + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".class extern")); + DumpComType((*g_pLocalComType)[ix],szString,GUICookie); + (*g_pLocalComType)[ix]->tkTypeDef = 0; + } + } + }//end if(nComTypes) + g_pAssemblyImport->CloseEnum(hEnum); + }//end if OK(EnumComTypes) + else nComTypes=0; +} + +// Replaces invalid characters and neutralizes reserved file names. +// Returns TRUE if the string was modified, FALSE otherwise. +static BOOL ConvertToLegalFileNameInPlace(__inout LPWSTR wzName) +{ + BOOL fAlias = FALSE; + + // neutralize reserved names + static const WCHAR * const rwzReserved[] = + { + L"COM", L"LPT", // '1' - '9' must follow after these + L"CON", L"PRN", L"AUX", L"NUL" + }; + + for (size_t i = 0; i < (sizeof(rwzReserved) / sizeof(WCHAR *)); i++) + { + _ASSERTE(wcslen(rwzReserved[i]) == 3); + if (_wcsnicmp(wzName, rwzReserved[i], 3) == 0) + { + LPWSTR pwc = wzName + 3; + + if (i <= 1) // COM, LPT + { + if (*pwc >= L'1' && *pwc <= L'9') + { + // skip the digit + pwc++; + } + else continue; + } + + // check for . or end of string + if (*pwc == L'.' || *pwc == 0) + { + *wzName = L'_'; + fAlias = TRUE; + break; + } + } + } + + // replace invalid characters + for (;; wzName++) + { + WCHAR wch = *wzName; + + if (wch > 0 && wch < 32) + { + *wzName = '~'; + fAlias = TRUE; + } + else + { + switch (wch) + { +#define REPLACE_CH(oldCh, newCh) \ + case oldCh: *wzName = newCh; \ + fAlias = TRUE; \ + break; + + REPLACE_CH(L':', L'!') + REPLACE_CH(L'\\', L'$') + REPLACE_CH(L',', L'&') // not necessary but keeping for back compat + REPLACE_CH(L';', L'@') // not necessary but keeping for back compat + REPLACE_CH(L'<', L'(') + REPLACE_CH(L'>', L')') + REPLACE_CH(L'"', L'`') + REPLACE_CH(L'/', L'_') + REPLACE_CH(L'|', L'-') + REPLACE_CH(L'*', L'+') // disallowed wildcard + REPLACE_CH(L'?', L'=') // disallowed wildcard + + case 0: return fAlias; +#undef REPLACE_CH + } + } + } +} + +// Dumps managed resource at pRes + dwOffset to a file. +static void DumpResourceFile(void *GUICookie, BYTE *pRes, DWORD dwOffset, LPCWSTR wzName, + LPCWSTR wzFileName, LPCUTF8 sz) +{ + struct Param + { + BYTE *pRes; + DWORD dwOffset; + LPCUTF8 sz; + void *GUICookie; + const WCHAR *wzFileName; + } param; + param.pRes = pRes; + param.dwOffset = dwOffset; + param.sz = sz; + param.GUICookie = GUICookie; + param.wzFileName = wzFileName; + + PAL_TRY(Param *, pParam, ¶m) + { + DWORD L; + memcpy(&L,pParam->pRes+pParam->dwOffset,sizeof(DWORD)); + sprintf_s(szString,SZSTRING_SIZE,COMMENT("%s// Offset: 0x%8.8X Length: 0x%8.8X"), g_szAsmCodeIndent,pParam->dwOffset,L); + printLine(pParam->GUICookie,szString); + if ((!(g_Mode & MODE_GUI)) && (g_pFile != NULL)) // embedded resource -- dump as .resources file + { + FILE *pF = NULL; + _wfopen_s(&pF, pParam->wzFileName, L"wb"); + if (pF) + { + struct Param + { + BYTE *pRes; + DWORD dwOffset; + DWORD L; + FILE *pF; + LPCUTF8 sz; + void *GUICookie; + } param; + param.pRes = pParam->pRes; + param.dwOffset = pParam->dwOffset; + param.L = L; + param.pF = pF; + param.sz = pParam->sz; + param.GUICookie = pParam->GUICookie; + + PAL_TRY(Param *, pParam, ¶m) { + fwrite((pParam->pRes+pParam->dwOffset+sizeof(DWORD)),pParam->L,1,pParam->pF); + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_W_CREATEDMRES),g_szAsmCodeIndent,ProperName(pParam->sz)); + printLine(pParam->GUICookie,COMMENT(szString)); + } + PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_READINGMRES),g_szAsmCodeIndent,ProperName(pParam->sz),pParam->dwOffset); + printError(pParam->GUICookie,szString); + } + PAL_ENDTRY + fclose(pF); + } + } + } + PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + sprintf_s(szString, SZSTRING_SIZE, + "ERROR retrieving/saving embedded managed resource '%s' at offset 0x%8.8X", + UnicodeToUtf(wzName), dwOffset); + printError(GUICookie, szString); + } + PAL_ENDTRY +} + +void DumpManifestResources(void* GUICookie) +{ + static mdManifestResource rManResTok[4096]; + ULONG nManRes = 0; + HCORENUM hEnum=NULL; + BYTE* pRes = NULL; + if(SUCCEEDED(g_pAssemblyImport->EnumManifestResources(&hEnum,rManResTok,4096,&nManRes))) + { + if(nManRes) + { + WCHAR* wzName = NULL; + ULONG ulNameLen=0; + DWORD dwFlags; + static char sz[4096]; + mdToken tkImplementation; + DWORD dwOffset; + + static WCHAR wzFileName[2048]; + + WszMultiByteToWideChar(CP_UTF8,0,g_szOutputFile,-1,wzFileName,2048); + wzName = wcsrchr(wzFileName,'\\'); + if(wzName == NULL) wzName = wcsrchr(wzFileName,':'); + if (wzName == NULL) wzName = wzFileName; + else wzName++; + + // remember the file names created so far to avoid duplicates + CQuickArray<CQuickWSTRBase> qbNameArray; + if (!qbNameArray.AllocNoThrow(nManRes + 2)) + { + sprintf_s(szString, SZSTRING_SIZE, + "ERROR retrieving/saving embedded managed resource '%s'", UnicodeToUtf(wzName)); + printError(GUICookie, szString); + return; + } + +#define NAME_ARRAY_ADD(index, str) \ + { \ + size_t __dwBufLen = wcslen(str) + 1; \ + \ + qbNameArray[index].Init(); \ + WCHAR *__wpc = (WCHAR *)qbNameArray[index].AllocNoThrow(__dwBufLen); \ + if (__wpc) wcscpy_s(__wpc, __dwBufLen, str); \ + } + + // add the output file name to avoid conflict between the IL file and a resource file + NAME_ARRAY_ADD(0, wzName); + + // add the Win32 resource file name to avoid conflict between the native and a managed resource file + WCHAR *pwc = wcsrchr(wzName, L'.'); + if (pwc == NULL) pwc = &wzName[wcslen(wzName)]; + wcscpy_s(pwc, 2048 - (pwc - wzFileName), L".res"); + + NAME_ARRAY_ADD(1, wzName); + + for(ULONG ix = 0; ix < nManRes; ix++) + { + ulNameLen=0; + if(SUCCEEDED(g_pAssemblyImport->GetManifestResourceProps( // S_OK or error. + rManResTok[ix], // [IN] The ManifestResource for which to get the properties. + wzName, // [OUT] Buffer to fill with name. + 1024, // [IN] Size of buffer in wide chars. + &ulNameLen, // [OUT] Actual # of wide chars in name. + &tkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ComType. + &dwOffset, // [OUT] Offset to the beginning of the resource within the file. + &dwFlags))) // [OUT] Flags. + { + sprintf_s(szString,SZSTRING_SIZE,"%s%s ",g_szAsmCodeIndent,KEYWORD(".mresource")); + if(g_fDumpTokens) sprintf_s(&szString[strlen(szString)],SZSTRING_SIZE-strlen(szString),COMMENT("/*%08X*/ "),rManResTok[ix]); + if(IsMrPublic(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("public ")); + if(IsMrPrivate(dwFlags)) strcat_s(szString,SZSTRING_SIZE,KEYWORD("private ")); + + char* pc = szString + strlen(szString); + wzName[ulNameLen]=0; + + WszWideCharToMultiByte(CP_UTF8,0,wzName,-1,sz,sizeof(sz),NULL,NULL); + strcpy_s(pc,SZSTRING_REMAINING_SIZE(pc),ProperName(sz)); + + // get rid of invalid characters and reserved names + BOOL fAlias = ConvertToLegalFileNameInPlace(wzName); + + // check for duplicate file name + WCHAR *wpc = wzName + wcslen(wzName); + for (int iIndex = 1;; iIndex++) + { + BOOL fConflict = FALSE; + if (*wzName == 0) + { + // resource with an empty name + fConflict = TRUE; + } + else + { + for (ULONG i = 0; i < (ix + 2); i++) + { + WCHAR *wzPreviousName = (WCHAR *)qbNameArray[i].Ptr(); + if (wzPreviousName && _wcsicmp(wzName, wzPreviousName) == 0) + { + // resource with the same name as another resource + // or with the same name as the output IL/RES file + fConflict = TRUE; + break; + } + } + } + + // if we have a conflict, add a number suffix to the file name + if (!fConflict || + swprintf_s(wpc, 2048 - (wpc - wzFileName), L"%d", iIndex) <= 0) + { + // no conflict or unable to add index + break; + } + + // try again with this new number suffix + fAlias = TRUE; + } + + // add this unique file name to the list + NAME_ARRAY_ADD(ix + 2, wzName); + + if(fAlias) + { + // update sz with the aliased name and print the 'as' keyword + if (WszWideCharToMultiByte(CP_UTF8, 0, wzName, -1, sz, sizeof(sz), NULL, NULL) == 0) + { + sz[sizeof(sz) - 1] = 0; + } + + pc=&szString[strlen(szString)]; + sprintf_s(pc,SZSTRING_REMAINING_SIZE(pc)," %s %s",KEYWORD("as"),ProperName(sz)); + } + + printLine(GUICookie,szString); + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,SCOPE()); + printLine(GUICookie,szString); + strcat_s(g_szAsmCodeIndent,MAX_MEMBER_LENGTH," "); + DumpCustomAttributes(rManResTok[ix], GUICookie); + + if(tkImplementation == mdFileNil) // embedded resource -- dump as .resources file + { + if(pRes == NULL) + { + // get the resource VA + if (g_pPELoader->getVAforRVA((DWORD) VAL32(g_CORHeader->Resources.VirtualAddress), (void **) &pRes) == FALSE) + { + printError(GUICookie,RstrUTF(IDS_E_IMPORTDATA)); + } + } + if(pRes) + { + DumpResourceFile(GUICookie, pRes, dwOffset, wzName, wzFileName, sz); + } + } + else DumpImplementation(tkImplementation,dwOffset,szString,GUICookie); + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-2] = 0; + sprintf_s(szString,SZSTRING_SIZE,"%s%s",g_szAsmCodeIndent,UNSCOPE()); + printLine(GUICookie,szString); + } //end if(OK(GetManifestResourceProps)) + }//end for(all manifest resources) + +#undef NAME_ARRAY_ADD + + }//end if(nManRes) + g_pAssemblyImport->CloseEnum(hEnum); + }//end if OK(EnumManifestResources) + else nManRes=0; +} + +// CLR internal hosting API +extern ICLRRuntimeHostInternal *g_pCLRRuntimeHostInternal; + +IMetaDataAssemblyImport* GetAssemblyImport(void* GUICookie) +{ + struct Param + { + void* GUICookie; + IMetaDataAssemblyImport* pAssemblyImport; + IMDInternalImport* pImport; + mdToken tkManifest; + } param; + param.GUICookie = GUICookie; + param.pAssemblyImport = NULL; + param.pImport = NULL; + + HRESULT hr; + + hr=g_pPubImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) ¶m.pAssemblyImport); + if(SUCCEEDED(hr)) + { + static mdAssemblyRef rAsmRefTok[4096]; + HCORENUM hEnum=NULL; + ULONG nAsmRefs = 0; + if(SUCCEEDED(param.pAssemblyImport->GetAssemblyFromScope(¶m.tkManifest))) return param.pAssemblyImport; + if(SUCCEEDED(param.pAssemblyImport->EnumAssemblyRefs(&hEnum,rAsmRefTok,4096,&nAsmRefs))) + { + param.pAssemblyImport->CloseEnum(hEnum); + if(nAsmRefs) return param.pAssemblyImport; + } + param.pAssemblyImport->Release(); + } + else + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_MDAIMPORT),hr); + printLine(GUICookie,COMMENT(szString)); + } + param.pAssemblyImport = NULL; + // OK, let's do it hard way: check if the manifest is hidden somewhere else + PAL_TRY(Param *, pParam, ¶m) + { + if(g_CORHeader->Resources.Size) + { + DWORD* pdwSize = NULL; + BYTE* pbManifest = NULL; + HRESULT hr; + + pbManifest = (BYTE*)(g_pPELoader->base() + (DWORD)VAL32(g_CORHeader->Resources.VirtualAddress)); + pdwSize = (DWORD*)pbManifest; + if(pdwSize && *pdwSize) + { + pbManifest += sizeof(DWORD); + if (SUCCEEDED(hr = g_pCLRRuntimeHostInternal->GetMetaDataInternalInterface( + pbManifest, + VAL32(*pdwSize), + ofRead, + IID_IMDInternalImport, + (LPVOID *)&pParam->pImport))) + { + if (FAILED(hr = g_pCLRRuntimeHostInternal->GetMetaDataPublicInterfaceFromInternal( + pParam->pImport, + IID_IMetaDataAssemblyImport, + (LPVOID *)&pParam->pAssemblyImport))) + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_MDAFROMMDI),hr); + printLine(pParam->GUICookie,COMMENT(szString)); + pParam->pAssemblyImport = NULL; + } + else + { + mdAssemblyRef rAsmRefTok[4096]; + HCORENUM hEnum=NULL; + ULONG nAsmRefs = 0; + if(FAILED(pParam->pAssemblyImport->GetAssemblyFromScope(&pParam->tkManifest)) + && (FAILED(pParam->pAssemblyImport->EnumAssemblyRefs(&hEnum,rAsmRefTok,4096,&nAsmRefs)) + || (nAsmRefs ==0))) + { + pParam->pAssemblyImport->CloseEnum(hEnum); + pParam->pAssemblyImport->Release(); + pParam->pAssemblyImport = NULL; + } + } + pParam->pImport->Release(); + } + else + { + sprintf_s(szString,SZSTRING_SIZE,RstrUTF(IDS_E_MDIIMPORT),hr); + printLine(pParam->GUICookie,COMMENT(szString)); + } + } + } + } // end try + PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + if(param.pAssemblyImport) param.pAssemblyImport->Release(); + param.pAssemblyImport = NULL; + if(param.pImport) param.pImport->Release(); + } + PAL_ENDTRY + return param.pAssemblyImport; +} + +static void DumpMetadataVersion(void* GUICookie) +{ + LPCSTR pVersionStr; + if (g_pImport == NULL || FAILED(g_pImport->GetVersionString(&pVersionStr))) + { + pVersionStr = "**Unavailable**"; + } + sprintf_s(szString,SZSTRING_SIZE,"// Metadata version: %s",pVersionStr); + printLine(GUICookie,szString); +} + +void DumpManifest(void* GUICookie) +{ + DumpMetadataVersion(GUICookie); + DumpModuleRefs(GUICookie); + if(g_pAssemblyImport==NULL) g_pAssemblyImport = GetAssemblyImport(GUICookie); + if(g_pAssemblyImport) + { + DumpAssemblyRefs(GUICookie); + DumpAssembly(GUICookie,TRUE); + DumpFiles(GUICookie); + DumpComTypes(GUICookie); + DumpManifestResources(GUICookie); + } + else printLine(GUICookie,COMMENT(RstrUTF(IDS_E_NOMANIFEST))); + DumpScope(GUICookie); + DumpVtable(GUICookie); + +} diff --git a/src/ildasm/dres.cpp b/src/ildasm/dres.cpp new file mode 100644 index 0000000000..d2c4191bf2 --- /dev/null +++ b/src/ildasm/dres.cpp @@ -0,0 +1,315 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// Win32 Resource extractor +// +#include "ildasmpch.h" + +#include "debugmacros.h" +#include "corpriv.h" +#include "dasmenum.hpp" +#include "dasmgui.h" +#include "formattype.h" +#include "dis.h" +#include "resource.h" +#include "ilformatter.h" +#include "outstring.h" + +#include "ceeload.h" +#include "dynamicarray.h" +extern IMAGE_COR20_HEADER * g_CORHeader; +extern IMDInternalImport* g_pImport; +extern PELoader * g_pPELoader; +extern IMetaDataImport2* g_pPubImport; +extern char g_szAsmCodeIndent[]; +extern unsigned g_uConsoleCP; + +struct ResourceHeader +{ + DWORD dwDataSize; + DWORD dwHeaderSize; + DWORD dwTypeID; + DWORD dwNameID; + DWORD dwDataVersion; + WORD wMemFlags; + WORD wLangID; + DWORD dwVersion; + DWORD dwCharacteristics; + ResourceHeader() + { + memset(this,0,sizeof(ResourceHeader)); + dwHeaderSize = sizeof(ResourceHeader); + dwTypeID = dwNameID = 0xFFFF; + }; +}; + +struct ResourceNode +{ + ResourceHeader ResHdr; + IMAGE_RESOURCE_DATA_ENTRY DataEntry; + WCHAR* wzType; + WCHAR* wzName; + ResourceNode(DWORD tid, DWORD nid, DWORD lid, DWORD dataOffset, BYTE* ptrBase) + { + if(tid & 0x80000000) + { + ResHdr.dwTypeID = 0; + tid &= 0x7FFFFFFF; + WORD L = *((WORD*)(ptrBase+tid)); + wzType = new WCHAR[L+1]; + memcpy(wzType,ptrBase+tid+sizeof(WORD),L*sizeof(WCHAR)); + wzType[L]=0; + } + else + { + ResHdr.dwTypeID = (0xFFFF |((tid & 0xFFFF)<<16)); + wzType = NULL; + } + + if(nid & 0x80000000) + { + ResHdr.dwNameID = 0; + nid &= 0x7FFFFFFF; + WORD L = *((WORD*)(ptrBase+nid)); + wzName = new WCHAR[L+1]; + memcpy(wzName, ptrBase+nid+sizeof(WORD), L*sizeof(WCHAR)); + wzName[L]=0; + } + else + { + ResHdr.dwNameID = (0xFFFF |((nid & 0xFFFF)<<16)); + wzName = NULL; + } + + //ResHdr.dwTypeID = (tid & 0x80000000) ? tid : (0xFFFF |((tid & 0xFFFF)<<16)); + //ResHdr.dwNameID = (nid & 0x80000000) ? nid : (0xFFFF |((nid & 0xFFFF)<<16)); + ResHdr.wLangID = (WORD)lid; + if(ptrBase) memcpy(&DataEntry,(ptrBase+dataOffset),sizeof(IMAGE_RESOURCE_DATA_ENTRY)); + ResHdr.dwDataSize = DataEntry.Size; + }; + ~ResourceNode() + { + if(wzType) VDELETE(wzType); + if(wzName) VDELETE(wzName); + }; + void Save(FILE* pF) + { + // Dump them to pF + BYTE* pbData; + DWORD dwFiller = 0; + BYTE bNil[3] = {0,0,0}; + // For each resource write header and data + if(g_pPELoader->getVAforRVA(VAL32(DataEntry.OffsetToData), (void **) &pbData)) + { + //fwrite(&(g_prResNodePtr[i]->ResHdr),g_prResNodePtr[i]->ResHdr.dwHeaderSize,1,pF); + ResHdr.dwHeaderSize = sizeof(ResourceHeader); + if(wzType) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzType) + 1)*sizeof(WCHAR) - sizeof(DWORD)); + if(wzName) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzName) + 1)*sizeof(WCHAR) - sizeof(DWORD)); + + //---- Constant part of the header: DWORD,DWORD + fwrite(&ResHdr.dwDataSize, sizeof(DWORD),1,pF); + fwrite(&ResHdr.dwHeaderSize, sizeof(DWORD),1,pF); + //--- Variable part of header: type and name + if(wzType) + { + fwrite(wzType,(wcslen(wzType) + 1)*sizeof(WCHAR), 1, pF); + dwFiller += (DWORD)wcslen(wzType) + 1; + } + else + fwrite(&ResHdr.dwTypeID,sizeof(DWORD),1,pF); + if(wzName) + { + fwrite(wzName,(wcslen(wzName) + 1)*sizeof(WCHAR), 1, pF); + dwFiller += (DWORD)wcslen(wzName) + 1; + } + else + fwrite(&ResHdr.dwNameID,sizeof(DWORD),1,pF); + + // Align remaining fields on DWORD + if(dwFiller & 1) + fwrite(bNil,2,1,pF); + + //---- Constant part of the header: DWORD,WORD,WORD,DWORD,DWORD + fwrite(&ResHdr.dwDataVersion,8*sizeof(WORD),1,pF); + //---- Header done, now data + fwrite(pbData,VAL32(DataEntry.Size),1,pF); + dwFiller = VAL32(DataEntry.Size) & 3; + if(dwFiller) + { + dwFiller = 4 - dwFiller; + fwrite(bNil,dwFiller,1,pF); + } + } + }; +}; + + +#define RES_FILE_DUMP_ENABLED + +DWORD DumpResourceToFile(__in __nullterminated WCHAR* wzFileName) +{ + + BYTE* pbResBase; + FILE* pF = NULL; + DWORD ret = 0; + DWORD dwResDirRVA; + DWORD dwResDirSize; + unsigned ulNumResNodes=0; + DynamicArray<ResourceNode*> g_prResNodePtr; + + if (g_pPELoader->IsPE32()) + { + IMAGE_OPTIONAL_HEADER32 *pOptHeader = &(g_pPELoader->ntHeaders32()->OptionalHeader); + + dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); + dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size); + } + else + { + IMAGE_OPTIONAL_HEADER64 *pOptHeader = &(g_pPELoader->ntHeaders64()->OptionalHeader); + + dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); + dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size); + } + + if(dwResDirRVA && dwResDirSize) + { + if(g_pPELoader->getVAforRVA(dwResDirRVA, (void **) &pbResBase)) + { + // First, pull out all resource nodes (tree leaves), see ResourceNode struct + PIMAGE_RESOURCE_DIRECTORY pirdType = (PIMAGE_RESOURCE_DIRECTORY)pbResBase; + PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeType = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbResBase+sizeof(IMAGE_RESOURCE_DIRECTORY)); + DWORD dwTypeID; + unsigned short i = 0,N = pirdType->NumberOfNamedEntries+pirdType->NumberOfIdEntries; + PAL_CPP_TRY { + for(i=0; i < N; i++, pirdeType++) + { + dwTypeID = VAL32(IMAGE_RDE_NAME(pirdeType)); + if(IMAGE_RDE_OFFSET_FIELD(pirdeType, DataIsDirectory)) + { + BYTE* pbNameBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeType, OffsetToDirectory)); + PIMAGE_RESOURCE_DIRECTORY pirdName = (PIMAGE_RESOURCE_DIRECTORY)pbNameBase; + PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeName = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbNameBase+sizeof(IMAGE_RESOURCE_DIRECTORY)); + DWORD dwNameID; + unsigned short i,N = VAL16(pirdName->NumberOfNamedEntries)+VAL16(pirdName->NumberOfIdEntries); + + for(i=0; i < N; i++, pirdeName++) + { + dwNameID = VAL32(IMAGE_RDE_NAME(pirdeName)); + if(IMAGE_RDE_OFFSET_FIELD(pirdeName, DataIsDirectory)) + { + BYTE* pbLangBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeName, OffsetToDirectory)); + PIMAGE_RESOURCE_DIRECTORY pirdLang = (PIMAGE_RESOURCE_DIRECTORY)pbLangBase; + PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeLang = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbLangBase+sizeof(IMAGE_RESOURCE_DIRECTORY)); + DWORD dwLangID; + unsigned short i,N = VAL16(pirdLang->NumberOfNamedEntries)+VAL16(pirdLang->NumberOfIdEntries); + + for(i=0; i < N; i++, pirdeLang++) + { + dwLangID = VAL32(IMAGE_RDE_NAME(pirdeLang)); + if(IMAGE_RDE_OFFSET_FIELD(pirdeLang, DataIsDirectory)) + { + _ASSERTE(!"Resource hierarchy exceeds three levels"); + } + else + { + g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,dwLangID, VAL32(IMAGE_RDE_OFFSET(pirdeLang)),pbResBase); + } + } + } + else + { + g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,0,VAL32(IMAGE_RDE_OFFSET(pirdeName)),pbResBase); + } + } + } + else + { + g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,0,0,VAL32(IMAGE_RDE_OFFSET(pirdeType)),pbResBase); + } + } + } PAL_CPP_CATCH_ALL { + ret= 0xDFFFFFFF; + ulNumResNodes = 0; + } + PAL_CPP_ENDTRY + // OK, all tree leaves are in ResourceNode structs, and ulNumResNodes ptrs are in g_prResNodePtr + if(ulNumResNodes) + { + ret = 1; +#ifdef RES_FILE_DUMP_ENABLED + + _wfopen_s(&pF,wzFileName,L"wb"); + if(pF) + { + // Dump them to pF + // Write dummy header + ResourceHeader *pRH = new ResourceHeader(); + fwrite(pRH,sizeof(ResourceHeader),1,pF); + SDELETE(pRH); + // For each resource write header and data + PAL_CPP_TRY { + for(i=0; i < ulNumResNodes; i++) + { + /* + sprintf_s(szString,SZSTRING_SIZE,"// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d", + i+1, + g_prResNodePtr[i]->ResHdr.dwTypeID, + g_prResNodePtr[i]->ResHdr.dwNameID, + g_prResNodePtr[i]->ResHdr.wLangID, + VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData), + VAL32(g_prResNodePtr[i]->DataEntry.Size)); + printLine(NULL,szString); + */ + g_prResNodePtr[i]->Save(pF); + SDELETE(g_prResNodePtr[i]); + } + } + PAL_CPP_CATCH_ALL { + ret= 0xDFFFFFFF; + } + PAL_CPP_ENDTRY + fclose(pF); + }// end if file opened + else ret = 0xEFFFFFFF; +#else + // Dump to text, using wzFileName as GUICookie + //char szString[4096]; + void* GUICookie = (void*)wzFileName; + BYTE* pbData; + printLine(GUICookie,""); + sprintf(szString,"// ========== Win32 Resource Entries (%d) ========",ulNumResNodes); + for(i=0; i < ulNumResNodes; i++) + { + printLine(GUICookie,""); + sprintf(szString,"// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d", + i+1, + g_prResNodePtr[i]->ResHdr.dwTypeID, + g_prResNodePtr[i]->ResHdr.dwNameID, + g_prResNodePtr[i]->ResHdr.wLangID, + VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData), + VAL32(g_prResNodePtr[i]->DataEntry.Size)); + printLine(GUICookie,szString); + if(g_pPELoader->getVAforRVA(VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData), (void **) &pbData)) + { + strcat(g_szAsmCodeIndent,"// "); + strcpy(szString,g_szAsmCodeIndent); + DumpByteArray(szString,pbData,VAL32(g_prResNodePtr[i]->DataEntry.Size),GUICookie); + printLine(GUICookie,szString); + g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-4] = 0; + } + SDELETE(g_prResNodePtr[i]); + } + ret = 1; +#endif + } // end if there are nodes + }// end if got ptr to resource + else ret = 0xFFFFFFFF; + } // end if there is resource + else ret = 0; + + return ret; +} diff --git a/src/ildasm/event.bmp b/src/ildasm/event.bmp Binary files differnew file mode 100644 index 0000000000..99c3357d95 --- /dev/null +++ b/src/ildasm/event.bmp diff --git a/src/ildasm/exe/ildasm.nativeproj b/src/ildasm/exe/ildasm.nativeproj new file mode 100644 index 0000000000..01a18a174c --- /dev/null +++ b/src/ildasm/exe/ildasm.nativeproj @@ -0,0 +1,71 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> + <!--Modify this before importing the clr-wide settings--> + <PropertyGroup> + <ClrDontIncludeAllInterfaces>true</ClrDontIncludeAllInterfaces> + </PropertyGroup> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + <!--Leaf project Properties--> + <PropertyGroup> + <UseAtl>true</UseAtl> + <AtlVer>mfc</AtlVer> + <EntryPoint>winmain</EntryPoint> + <LinkSubsystem>console</LinkSubsystem> + + <!-- PCH baloney --> + <EnableCxxPCHHeaders>true</EnableCxxPCHHeaders> + <PCHCompile>..\ildasmpch.cpp</PCHCompile> + <PCHHeader>ildasmpch.h</PCHHeader> + + <CDefines>$(CDefines);__TODO_PORT_TO_WRAPPERS__</CDefines> + <LinkUseCMT>true</LinkUseCMT> + <UseMsvcrt>false</UseMsvcrt> + </PropertyGroup> + + <PropertyGroup> + <UserIncludes>$(UserIncludes);.;$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\tools\metainfo</UserIncludes> + <CDefines>$(CDefines);UNICODE;_UNICODE;FEATURE_NO_HOST;__ILDASM__</CDefines> + <OutputName>ildasm</OutputName> + <FileToMarkForSigning>$(BinariesDirectory)\ildasm.exe</FileToMarkForSigning> + <TargetType>PROGRAM</TargetType> + <LinkGenerateManifest/> + </PropertyGroup> + + <!--Leaf Project Items--> + <ItemGroup> + <LinkPreCrtLibs Include="$(ClrLibPath)\utilcodestaticnohost.lib"> + <ProjectReference>$(ClrSrcDirectory)utilcode\staticnohost\staticnohost.nativeproj</ProjectReference> + </LinkPreCrtLibs> + <LinkPreCrtLibs Include="$(ClrLibPath)\MDHotData.lib"> + <ProjectReference>$(ClrSrcDirectory)md\hotdata\full\mdhotdata.nativeproj</ProjectReference> + </LinkPreCrtLibs> + <TargetLib Include="$(ClrLibPath)\corguids.lib"> + <ProjectReference>$(ClrSrcDirectory)inc\corguids.nativeproj</ProjectReference> + </TargetLib> + <TargetLib Include="$(SdkLibPath)\mscoree.lib" /> + <TargetLib Include="$(SdkLibPath)\gdi32.lib" /> + <TargetLib Include="$(SdkLibPath)\comctl32.lib" /> + <TargetLib Include="$(SdkLibPath)\comdlg32.lib" /> + <TargetLib Include="$(SdkLibPath)\ole32.lib" /> + <TargetLib Include="$(SdkLibPath)\uuid.lib" /> + <TargetLib Include="$(SdkLibPath)\user32.lib" /> + <TargetLib Include="$(SdkLibPath)\shell32.lib" /> + <TargetLib Include="$(SdkLibPath)\oleaut32.lib" /> + <TargetLib Include="$(SdkLibPath)\htmlhelp.lib" /> + </ItemGroup> + <ItemGroup> + <RCResourceFile Include="..\dasm.rc" /> + <CppCompile Include="..\dasm_pr.cpp" /> + <CppCompile Include="..\gui.cpp" /> + <CppCompile Include="..\dis.cpp" /> + <CppCompile Include="..\dman.cpp" /> + <CppCompile Include="..\dres.cpp" /> + <CppCompile Include="..\ceeload.cpp" /> + <CppCompile Include="..\dasm_formatType.cpp" /> + <CppCompile Include="..\dasm_mi.cpp" /> + <CppCompile Include="..\dasm_sz.cpp" /> + <CppCompile Include="..\dasm.cpp" /> + <CppCompile Include="..\windasm.cpp" /> + <DataFile Include="..\ildasm.chm" /> + </ItemGroup> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> diff --git a/src/ildasm/field.bmp b/src/ildasm/field.bmp Binary files differnew file mode 100644 index 0000000000..aa09fb2f54 --- /dev/null +++ b/src/ildasm/field.bmp diff --git a/src/ildasm/gui.cpp b/src/ildasm/gui.cpp new file mode 100644 index 0000000000..14131a83a3 --- /dev/null +++ b/src/ildasm/gui.cpp @@ -0,0 +1,4013 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "ildasmpch.h" + +#include "debugmacros.h" +#include "corpriv.h" +#include "ceeload.h" +#include "dasmgui.h" +#include "dasmenum.hpp" +#include "dis.h" +#include "resource.h" +#include "gui.h" +#include "formattype.h" +#include "..\tools\metainfo\mdinfo.h" +#include <NdpVersion.h> + +struct MemberInfo { + const char *pszMemberName; + DWORD dwAttrs; + ULONG cComSig; + PCCOR_SIGNATURE pComSig; + mdToken token; +}; + +int __cdecl memberCmp(const void *elem1, const void *elem2 ) { + MemberInfo* mem1 = (MemberInfo*) elem1; + MemberInfo* mem2 = (MemberInfo*) elem2; + return(strcmp(mem1->pszMemberName, mem2->pszMemberName)); +} + +// +// Global buffer, filled by AddOPCode +// +char *GlobalBuffer = new (nothrow) char[65535]; +ULONG GlobalBufferLen = 65535; +ULONG InGlobalBuffer; +// +// Global HINSTANCE +// +extern HINSTANCE g_hInstance; +HINSTANCE g_hResources; + +// +// Main window +// +HWND g_hwndMain; + +// +// Treeview for main window +// +HWND g_hwndTreeView; + +// +// Treeview class full name / partial name switch +// +BOOL g_fTreeViewFCN = TRUE; + +// +// Assembly info window (child of main) +// +HWND g_hwndAsmInfo; +extern IMetaDataAssemblyImport* g_pAssemblyImport; +void DumpAssembly(void* GUICookie, BOOL fFullDump); +IMetaDataAssemblyImport* GetAssemblyImport(void* GUICookie); + +// +// Global image list +// +HIMAGELIST g_hImageList; + +// +// Menu for main window +// +HMENU g_hMenu, g_hMetaInfoMenu, g_hFileMenu, g_hViewMenu, g_hFontMenu; + +// +// Flags +// +BOOL g_fFullMemberInfo = FALSE; // Show member type? (method, field, event, prop) +BOOL g_fSortByName = TRUE; // Sort members in tree? +// +// Module name of loaded DLL/EXE +// +const char *g_pszModule; + +// +// Interlocked variable for setting char dimensions once +// +long g_SetCharDimensions = 0; + +unsigned g_uFindReplaceMsg = 0; +HWND g_hFindText = NULL; +// +// Bitmap handles +// +HBITMAP g_hBitmaps[LAST_IMAGE_INDEX]; + +// +// Root item for listview +// +HTREEITEM g_hRoot; + +// Global graphics +HBRUSH g_hWhiteBrush; +HFONT g_hFixedFont; +HFONT g_hSmallFont; +HBITMAP g_hMethodBmp, g_hFieldBmp, g_hClassBmp, g_hStaticMethodBmp, g_hStaticFieldBmp, g_hQuestionBmp; +LOGFONTW g_strLogFontTree, g_strLogFontDasm; +CHOOSEFONTW g_strChFontTree, g_strChFontDasm; + +struct GUI_Info +{ + LOGFONTW* plfTree; + LOGFONTW* plfDasm; + int x; + int y; + int w; + int h; +}; + +GUI_Info guiInfo = {&g_strLogFontTree, &g_strLogFontDasm, CW_USEDEFAULT, CW_USEDEFAULT, 400,600}; + +// Text info +long g_Height; +long g_MaxCharWidth; + +// Currently selected treeview item +HTREEITEM g_CurSelItem; + +extern IMAGE_COR20_HEADER * g_CORHeader; +extern BOOL g_fDumpTokens; +extern BOOL g_fShowBytes; +extern BOOL g_fShowSource; +extern BOOL g_fTryInCode; +extern BOOL g_fQuoteAllNames; +extern BOOL g_fCAVerbal; +extern BOOL g_fShowProgressBar; +extern BOOL g_fDumpHeader; +extern BOOL g_fDumpAsmCode; +extern BOOL g_fDumpTokens; +extern BOOL g_fDumpStats; +extern BOOL g_fDumpMetaInfo; +extern BOOL g_fDumpClassList; +extern BOOL g_fInsertSourceLines; + +extern BOOL g_fLimitedVisibility; +extern BOOL g_fHidePub; +extern BOOL g_fHidePriv; +extern BOOL g_fHideFam; +extern BOOL g_fHideAsm; +extern BOOL g_fHideFAA; +extern BOOL g_fHideFOA; +extern BOOL g_fHidePrivScope; +extern BOOL g_fTDC; + +extern char g_szInputFile[]; // in UTF-8 +extern WCHAR g_wszFullInputFile[]; // in UTF-16 +extern ULONG g_ulMetaInfoFilter; +extern char g_szOutputFile[]; // in UTF-8 +extern DWORD g_Mode; +extern FILE* g_pFile; +extern HINSTANCE g_hInstance; + +extern unsigned g_uCodePage; +extern unsigned g_uConsoleCP; +DWORD DumpResourceToFile(__in __nullterminated WCHAR* wzFileName); // see DRES.CPP +// +// Functions +// +BOOL RegisterWindowClasses(); +HWND CreateTreeView(HWND hwndParent); +HTREEITEM AddOneItem(HTREEITEM hParent, const char *pszText, HTREEITEM hInsAfter, int iImage, HWND hwndTree, BOOL fExpanded); +HWND GUIDisassemble(mdTypeDef cl, mdToken mbMember, __in __nullterminated char *pszWindowTitle); +HTREEITEM AddClassToTreeView(HTREEITEM hParent, mdTypeDef cl); +void AddGlobalFunctions(); +void CreateMenus(); +Namespace_t* FindNamespace(const char *pszNamespace); +void GUICleanupClassItems(); +void SelectClassByName(__in __nullterminated char *pszFQName); +void SelectClassByToken(mdToken tk); +void DumpTreeItem(HTREEITEM hItem, FILE* pFile, __inout __nullterminated WCHAR* szIndent); +HTREEITEM FindCreateNamespaceRoot(const char *pszNamespace); +FILE* OpenOutput(__in __nullterminated const char* szFileName); +FILE* OpenOutput(__in __nullterminated const WCHAR* wzFileName); + +#undef SendMessageW +#undef PostMessageW +#undef CreateWindowExW +#undef DefWindowProcW +#undef RegisterClassExW +#undef RegisterClassW +#undef SetWindowTextW +#undef GetWindowTextW +#undef MessageBoxW + +char* UtfToAnsi(__in __nullterminated const char* sz) { return UnicodeToAnsi(UtfToUnicode(sz));} + +LRESULT CALLBACK DisassemblyWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +); + +LRESULT CALLBACK MainWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +); + +ClassItem_t *AddClassToGUI(mdTypeDef cl, UINT uImageIndex, + const char *pszNamespace, const char *pszClassName, DWORD cSubItems, HTREEITEM *phRoot); + +void AddMethodToGUI( + mdTypeDef cl, + ClassItem_t * pClassItem, + const char *pszNamespace, + const char *pszClassName, + const char *pszMethodName, + PCCOR_SIGNATURE pComSig, + unsigned cComSig, + mdMethodDef mbMethod, + DWORD dwAttrs +); + +void AddFieldToGUI( + mdTypeDef cl, + ClassItem_t *pClassItem, + const char *pszNamespace, + const char *pszClassName, + const char *pszFieldName, + const char *pszSignature, + mdFieldDef mbField, + DWORD dwAttrs +); + +void AddEventToGUI( + mdTypeDef cl, + ClassItem_t *pClassItem, + const char *pszNamespace, + const char *pszClassName, + DWORD dwClassAttrs, + mdEvent mbEvent +); + +void AddPropToGUI( + mdTypeDef cl, + ClassItem_t *pClassItem, + const char *pszNamespace, + const char *pszClassName, + DWORD dwClassAttrs, + mdProperty mbProp +); + +DynamicArray<DisasmBox_t> *g_DisasmBox; +DWORD g_NumDisasmBoxes=0; + +DynamicArray<ClassItem_t> *g_ClassItemList; +DWORD g_NumClassItems=0; + +DynamicArray<Namespace_t> *g_NamespaceList; +DWORD g_NumNamespaces=0; + + +ClassItem_t *FindClassItem(HTREEITEM hItem); +ClassItem_t *FindClassItem(mdTypeDef cl); +ClassItem_t *FindClassItem(__in_opt __nullterminated char *pszNamespace, __in __nullterminated char *pszName); + +// Find disasm box among opened by class and member tokens +DisasmBox_t* FindDisasmBox(mdToken tkClass, mdToken tkMember) +{ + for (DWORD i = 0; i < g_NumDisasmBoxes; i++) + { + if (((*g_DisasmBox)[i].tkClass == tkClass) + &&((*g_DisasmBox)[i].tkMember == tkMember)) + return &(*g_DisasmBox)[i]; + } + return NULL; +} +// Find disasm box among opened by the container hwnd +DisasmBox_t* FindDisasmBoxByHwnd(HWND hwndContainer) +{ + for (DWORD i = 0; i < g_NumDisasmBoxes; i++) + { + if ((*g_DisasmBox)[i].hwndContainer == hwndContainer) + return &(*g_DisasmBox)[i]; + } + return NULL; +} +// +// Add a new disassembly box to the global list of them +// +// hwndContainer - parent window +// hwndChild - listview +// +void AddDisasmBox(HWND hwndContainer, HWND hwndChild, HMENU hMenu, mdToken tkClass, mdToken tkMember) +{ + (*g_DisasmBox)[g_NumDisasmBoxes].hwndContainer = hwndContainer; + (*g_DisasmBox)[g_NumDisasmBoxes].hwndChild = hwndChild; + (*g_DisasmBox)[g_NumDisasmBoxes].hMenu = hMenu; + (*g_DisasmBox)[g_NumDisasmBoxes].tkClass = tkClass; + (*g_DisasmBox)[g_NumDisasmBoxes].tkMember = tkMember; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.lStructSize = sizeof(FINDREPLACEW); + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.hwndOwner = hwndContainer; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.Flags = FR_DOWN|FR_DIALOGTERM; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.lpstrFindWhat = (LPWSTR)((*g_DisasmBox)[g_NumDisasmBoxes].wzFind); + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.lpstrReplaceWith = NULL; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.wFindWhatLen = 120; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.wReplaceWithLen = 0; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.lCustData = 0; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.lpfnHook = NULL; + (*g_DisasmBox)[g_NumDisasmBoxes].strFR.lpTemplateName = NULL; + g_NumDisasmBoxes++; +} + +void UpdateDisasmBox(DisasmBox_t* pBox, HWND hwndContainer, HWND hwndChild, HMENU hMenu) +{ + pBox->hwndContainer = hwndContainer; + pBox->hwndChild = hwndChild; + pBox->hMenu = hMenu; + pBox->strFR.hwndOwner = hwndContainer; +} +// +// Given a container window, find the associated disassembly window +// +HWND FindAssociatedDisassemblyListBox(HWND hwndContainer) +{ + DWORD i; + + for (i = 0; i < g_NumDisasmBoxes; i++) + { + if ((*g_DisasmBox)[i].hwndContainer == hwndContainer) + return (*g_DisasmBox)[i].hwndChild; + } + + return NULL; +} + +// +// Given a disassembly window, find the associated container window +// +HWND FindAssociatedDisassemblyContainer(HWND hwndChild) +{ + DWORD i; + + for (i = 0; i < g_NumDisasmBoxes; i++) + { + if ((*g_DisasmBox)[i].hwndChild == hwndChild) + return (*g_DisasmBox)[i].hwndContainer; + } + + return NULL; +} + + +void RemoveDisasmBox(HWND hwndContainer) +{ + DWORD i; + + for (i = 0; i < g_NumDisasmBoxes; i++) + { + if ((*g_DisasmBox)[i].hwndContainer == hwndContainer) + { + memcpy(&(*g_DisasmBox)[i], &(*g_DisasmBox)[i+1], (g_NumDisasmBoxes-i-1)*sizeof(DisasmBox_t)); + g_NumDisasmBoxes--; + break; + } + } +} + + +void RemoveItemsFromList() +{ + TreeView_DeleteAllItems(g_hwndTreeView); +} + + +BOOL RefreshList() +{ + GUICleanupClassItems(); + return GUIAddItemsToList(); +} + + +void GUISetModule(__in __nullterminated const char *pszModule) +{ + g_pszModule = pszModule; +} + + +TreeItem_t *FindClassMemberByName(ClassItem_t *pClassItem, + __in __nullterminated char *pszFindName, + __in __nullterminated char *pszFindSig) +{ + HRESULT hr; + DWORD i; + + // do in two passes, fields first + for (i = 0; i < pClassItem->SubItems; i++) + { + TreeItem_t *pItem; + const char *pszMemberName; + const char *pszMemberSig; + DWORD dwAttrs; + + CQuickBytes qbMemberSig; + + PCCOR_SIGNATURE pComSig; + ULONG cComSig; + + + pItem = &pClassItem->pMembers[i]; + if (pItem->Discriminator != TREEITEM_TYPE_MEMBER) + continue; + + if (TypeFromToken(pItem->mbMember) == mdtMethodDef) + { + if (FAILED(g_pImport->GetMethodDefProps(pItem->mbMember, &dwAttrs))) + { + continue; + } + if (FAILED(g_pImport->GetNameOfMethodDef(pItem->mbMember, &pszMemberName))) + { + continue; + } + if (FAILED(g_pImport->GetSigOfMethodDef(pItem->mbMember, &cComSig, &pComSig))) + { + continue; + } + } + else + { + if (FAILED(g_pImport->GetFieldDefProps(pItem->mbMember, &dwAttrs))) + { + continue; + } + if (FAILED(g_pImport->GetNameOfFieldDef(pItem->mbMember, &pszMemberName))) + { + continue; + } + if (FAILED(g_pImport->GetSigOfFieldDef(pItem->mbMember, &cComSig, &pComSig))) + { + continue; + } + } + MAKE_NAME_IF_NONE(pszMemberName,pItem->mbMember); + qbMemberSig.Shrink(0); + pszMemberSig = PrettyPrintSig(pComSig, cComSig, "", &qbMemberSig, g_pImport,NULL); + + // @todo: GUI IL is so that NDView can call into DASM with/GUI; NDView uses Reflection API + // which doesn't let us get a valid signature. + // If GUI IL only, then ignore signature if it's NULL + if (IsGuiILOnly()) { + if (!strcmp(pszMemberName, pszFindName)) { + if ((pszFindSig != NULL) && strcmp(pszMemberSig, pszFindSig)) continue; + return pItem; + } + } else { + if (!strcmp(pszMemberName, pszFindName) && !strcmp(pszMemberSig, pszFindSig)) + return pItem; + } + } + + return NULL; +} + +// Kick of a disassembly window +// Return TRUE if window opened ok, and FALSE if there's an error +BOOL DisassembleMemberByName(__in __nullterminated char *pszClassName, + __in __nullterminated char *pszMemberName, + __in_opt __nullterminated char *pszSig) +{ + char szClassName[MAX_CLASSNAME_LENGTH]; + char szClassNamespace[MAX_CLASSNAME_LENGTH]; + char *pszClassNamespace; + char *p; + + p = ns::FindSep(pszClassName); + if (p == NULL) + { + strcpy_s(szClassName, MAX_CLASSNAME_LENGTH,pszClassName); + pszClassNamespace = NULL; + } + else + { + strncpy_s(szClassNamespace, MAX_CLASSNAME_LENGTH, pszClassName, p - pszClassName); + szClassNamespace[ p - pszClassName ] = '\0'; + pszClassNamespace = szClassNamespace; + + strcpy_s(szClassName, MAX_CLASSNAME_LENGTH, p+1); + } + + ClassItem_t *pClassItem = FindClassItem(pszClassNamespace, szClassName); + + if (pClassItem != NULL) + { + TreeItem_t *pTreeItem; + + pTreeItem = FindClassMemberByName(pClassItem, pszMemberName, pszSig); + + if (pTreeItem != NULL) + { + DWORD dwAttrs; + DWORD dwImplAttrs; + + // What is this member? + + if (TypeFromToken(pTreeItem->mbMember) == mdtMethodDef) + { + char* szText; + HWND fOK=NULL; + if (FAILED(g_pImport->GetMethodDefProps(pTreeItem->mbMember, &dwAttrs))) + { + goto ErrorHere; + } + if (FAILED(g_pImport->GetMethodImplProps(pTreeItem->mbMember, NULL, &dwImplAttrs))) + { + goto ErrorHere; + } + + // Can't be abstract or native + if (IsMdAbstract(dwAttrs) || IsMiInternalCall(dwImplAttrs)) + return FALSE; + + szText = new (nothrow) char[4096]; + if(szText) + { + TVITEMA SelItem; + + // Get the name of this item so that we can title the disassembly window + memset(&SelItem, 0, sizeof(SelItem)); + SelItem.mask = TVIF_TEXT; + SelItem.pszText = szText; + SelItem.hItem = pTreeItem->hItem; + SelItem.cchTextMax = 4095; + + WCHAR* wzText = (WCHAR*)szText; + SendMessageW(g_hwndTreeView, TVM_GETITEMW, 0, (LPARAM) (LPTVITEMW) &SelItem); + unsigned L = ((unsigned)wcslen(wzText)+1)*3; + char* szUTFText = new (nothrow) char[L]; + if(szUTFText) + { + memset(szUTFText,0,L); + WszWideCharToMultiByte(CP_UTF8,0,wzText,-1,szUTFText,L,NULL,NULL); + delete[] wzText; + szText = szUTFText; + } + + fOK = GUIDisassemble(pClassItem->cl, pTreeItem->mbMember, szText); + delete[] szText; + } + if (fOK == NULL) { + goto ErrorHere; + } + } + } // endif (pTreeItem != NULL) + else { + goto ErrorHere; + } + + } else { + goto ErrorHere; + } + + return TRUE; + +ErrorHere: + char pzText[300]; + sprintf_s(pzText, 300,RstrUTF(IDS_CANTVIEW_TX) /*"Can't view %s::%s(%s)"*/, pszClassName, pszMemberName, pszSig); + + WszMessageBox(g_hwndMain, UtfToUnicode(pzText), RstrW(IDS_CANTVIEW_HD) /*"Can't View IL"*/, MB_OK | MB_ICONERROR | GetDasmMBRTLStyle() ); + + + return FALSE; +} + +//HTREEITEM AddInfoItemToClass(HTREEITEM hParent, ClassItem_t *pClassItem, const char *pszText, const char *pszStoredInfoText) +HTREEITEM AddInfoItemToClass(HTREEITEM hParent, ClassItem_t *pClassItem, const char *pszText, mdToken tk) +{ + _ASSERTE(pClassItem->CurMember < pClassItem->SubItems); + pClassItem->pMembers[pClassItem->CurMember].hItem = AddOneItem( + pClassItem->hItem, pszText, hParent, RED_ARROW_IMAGE_INDEX, g_hwndTreeView, FALSE + ); + pClassItem->pMembers[pClassItem->CurMember].Discriminator = TREEITEM_TYPE_INFO; + //pClassItem->pMembers[pClassItem->CurMember].pszText = (char *) pszStoredInfoText; + pClassItem->pMembers[pClassItem->CurMember].mbMember = tk; + pClassItem->CurMember++; + + return pClassItem->pMembers[pClassItem->CurMember-1].hItem; +} + +struct ClassDescr +{ + mdToken tk; + const char* szName; +}; +static int __cdecl classDescrCmp(const void *op1, const void *op2) +{ + return strcmp(((ClassDescr*)op1)->szName,((ClassDescr*)op2)->szName); +} + +unsigned AddClassesWithEncloser(mdToken tkEncloser, HTREEITEM hParent) +{ + unsigned i, N=0; + for (i = 0; i < g_NumClasses; i++) + { + if(g_cl_enclosing[i] == tkEncloser) N++; + } + + if(N) + { + ClassDescr* rClassDescr = new (nothrow) ClassDescr[N]; + const char *pszClassName,*pszNamespace; + for (i = 0, N = 0; i < g_NumClasses; i++) + { + if(g_cl_enclosing[i] == tkEncloser) + { + rClassDescr[N].tk = g_cl_list[i]; + if (FAILED(g_pImport->GetNameOfTypeDef(g_cl_list[i], &pszClassName, &pszNamespace))) + { + pszClassName = pszNamespace = "Invalid TypeDef record"; + } + // doesn't throw here, so rClassDescr doesn't leak + MAKE_NAME_IF_NONE(pszClassName,g_cl_list[i]); + rClassDescr[N].szName = pszClassName; + N++; + } + } + if(g_fSortByName) qsort(&rClassDescr[0],N,sizeof(ClassDescr),classDescrCmp); + for(i = 0; i < N; i++) AddClassToTreeView(hParent,rClassDescr[i].tk); + delete[] rClassDescr; + } + return N; +} + +static int __cdecl stringCmp(const void *op1, const void *op2) +{ + return strcmp(*((char**)op1), *((char**)op2)); + //return(strlen(*((char**)op1)) - strlen(*((char**)op2))); +} + +UINT GetDasmMBRTLStyle() { + UINT RTLMessageBoxStyle = 0; + WCHAR* pwStr = RstrW(IDS_RTL); + if( wcscmp(pwStr, L"RTL_True") == 0) { + RTLMessageBoxStyle = 0x00080000 |0x00100000; // MB_RIGHT || MB_RTLREADING + } + return RTLMessageBoxStyle; +} + +void GUIDumpAssemblyInfo() +{ + memset(GlobalBuffer,0,GlobalBufferLen); + InGlobalBuffer = 0; + if(g_pAssemblyImport==NULL) g_pAssemblyImport = GetAssemblyImport((void*)g_hwndAsmInfo); + if(g_pAssemblyImport) + { + if(g_fDumpRTF) DumpRTFPrefix((void *)g_hwndAsmInfo,FALSE); + DumpAssembly((void *)g_hwndAsmInfo,FALSE); + if(g_fDumpRTF) DumpRTFPostfix((void *)g_hwndAsmInfo); + } + + if(g_uCodePage == 0xFFFFFFFF) + SendMessageW((HWND)g_hwndAsmInfo,WM_SETTEXT,0, (LPARAM)GlobalBuffer); + else + { + UINT32 L = (UINT32)strlen(GlobalBuffer); + WCHAR* wz = new (nothrow) WCHAR[L+4]; + if(wz) + { + memset(wz,0,sizeof(WCHAR)*(L+2)); + int x = WszMultiByteToWideChar(CP_UTF8,0,GlobalBuffer,-1,wz,L+2); + if(g_fDumpRTF) + { + x = (int)SendMessageA((HWND)g_hwndAsmInfo,WM_SETTEXT,0, (LPARAM)UnicodeToAnsi(wz)); + } + else + { + x = (int)WszSendMessage((HWND)g_hwndAsmInfo,WM_SETTEXT,0, (LPARAM)wz); + } + delete[] wz; + } + } +} + +BOOL GUIAddItemsToList() +{ + DWORD i,NumGlobals=0; + HENUMInternal hEnumMethod; + + RemoveItemsFromList(); + g_NumClassItems = 0; + g_NumNamespaces = 0; + + g_hRoot = AddOneItem( + (HTREEITEM)NULL, + g_pszModule, + (HTREEITEM)TVI_ROOT, + FIELD_IMAGE_INDEX, + g_hwndTreeView, + TRUE + ); + + if (SUCCEEDED(g_pImport->EnumGlobalFunctionsInit(&hEnumMethod))) + { + NumGlobals = g_pImport->EnumGetCount(&hEnumMethod); + g_pImport->EnumClose(&hEnumMethod); + } + if (SUCCEEDED(g_pImport->EnumGlobalFieldsInit(&hEnumMethod))) + { + NumGlobals += g_pImport->EnumGetCount(&hEnumMethod); + g_pImport->EnumClose(&hEnumMethod); + } + (*g_ClassItemList)[0].hItem = g_hRoot; + (*g_ClassItemList)[0].cl = 0; + (*g_ClassItemList)[0].SubItems = NumGlobals+1; + (*g_ClassItemList)[0].CurMember = 0; + (*g_ClassItemList)[0].pMembers = new (nothrow) TreeItem_t[NumGlobals+1]; + g_NumClassItems++; + + //AddInfoItemToClass((HTREEITEM)TVI_ROOT, &(*g_ClassItemList)[0], " M A N I F E S T", "__MANIFEST__"); + AddInfoItemToClass((HTREEITEM)TVI_ROOT, &(*g_ClassItemList)[0], " M A N I F E S T", 0xFFFFFFFF); + + if (g_NumClasses != 0) + { + //create root namespaces + { + char** rszNamespace = new (nothrow) char*[g_NumClasses]; + ULONG ulNamespaces=0; + for (i = 0; i < g_NumClasses; i++) + { + if (g_cl_enclosing[i] == mdTypeDefNil) // nested classes don't have separate namespaces + { + const char *pszClassName, *pszNameSpace; + if (FAILED(g_pImport->GetNameOfTypeDef( + g_cl_list[i], + &pszClassName, + &pszNameSpace))) + { + pszClassName = pszNameSpace = "Invalid TypeDef record"; + } + if ((pszNameSpace != NULL) && (*pszNameSpace != 0)) + { + rszNamespace[ulNamespaces++] = (char*)pszNameSpace; + } + } + } + if (ulNamespaces != 0) + { + qsort(&rszNamespace[0],ulNamespaces,sizeof(char*),stringCmp); + for(i = 0; i < ulNamespaces; i++) FindCreateNamespaceRoot(rszNamespace[i]); + } + delete[] rszNamespace; + } + AddClassesWithEncloser(mdTypeDefNil,NULL); + }// end if (g_NumClasses) + AddGlobalFunctions(); + + WszSendMessage(g_hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)g_hRoot); + EnableMenuItem(g_hMenu,(UINT)(UINT_PTR)g_hViewMenu, MF_ENABLED); + EnableMenuItem(g_hFileMenu,IDM_DUMP,MF_ENABLED); + EnableMenuItem(g_hFileMenu,IDM_DUMP_TREE,MF_ENABLED); + DrawMenuBar(g_hwndMain); + + { + WszMultiByteToWideChar(CP_UTF8,0,g_szInputFile,-1,wzUniBuf,2048); + wcscat_s(wzUniBuf,2048,L" - IL DASM"); + for(int cnt=0; cnt<100; cnt++) + { + SendMessageW(g_hwndMain,WM_SETTEXT, 0, (LPARAM)wzUniBuf); + SendMessageW(g_hwndMain,WM_GETTEXT, 2048, (LPARAM)&wzUniBuf[2048]); + wzUniBuf[2047]=0; + if(0 == wcscmp(wzUniBuf,&wzUniBuf[2048])) break; + } + } + + if (IsGuiILOnly()) { + ShowWindow(g_hwndMain, SW_HIDE); + } else { + ShowWindow(g_hwndMain, SW_SHOW); + } + UpdateWindow(g_hwndMain); + //GUIDisassemble(0,0,"MANIFEST"); + g_Mode &= ~MODE_GUI; + DumpManifest(NULL); + g_Mode |= MODE_GUI; + + GUIDumpAssemblyInfo(); + + TreeView_SelectItem(g_hwndTreeView,g_hRoot); + SetFocus(g_hwndTreeView); + return TRUE; +} + + +// +// Find class item by class token +// +ClassItem_t* ClassItemByToken(mdTypeDef cl) +{ + for(ULONG i=0; i < g_NumClassItems; i++) + { + if((*g_ClassItemList)[i].cl == cl) return &(*g_ClassItemList)[i]; + } + return NULL; +} + +// Factored out of AddClassToTreeView for its big stack consumption (AddClassToTreeView is +// called recursively via AddClassesWithEncloser). +static void AddClassToTreeView_PrettyPrintClass(mdTypeRef crType, LPCUTF8 pszFormat, __out_ecount(cBufferSize) char *pszBuffer, size_t cBufferSize) +{ + CQuickBytes out; + sprintf_s(pszBuffer, cBufferSize, pszFormat, PrettyPrintClass(&out, crType, g_pImport)); +} + +// +// Add a class and its members +// +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +HTREEITEM AddClassToTreeView(HTREEITEM hParent, mdTypeDef cl) +{ + HRESULT hr; + ClassItem_t *pClassItem; + HTREEITEM hClassRoot; + HTREEITEM hNamespaceRoot = hParent; + HTREEITEM hPrimaryInfo; + HTREEITEM hLast; + mdToken *pMemberList = NULL; + HENUMInternal hEnumMethod; // enumerator for method defs + HENUMInternal hEnumField; // enumerator for fields + HENUMInternal hEnumEvent; // enumerator for events + HENUMInternal hEnumProp; // enumerator for properties + DWORD NumMembers; + const char *pszClassName; // name associated with this CL + const char *pszNamespace; + DWORD dwClassAttrs; + mdTypeRef crExtends; + mdInterfaceImpl ii; + DWORD NumInterfaces; + DWORD i; + char *szPrimaryInfo; // public class foo extends bar +// char *szFullClassName; + DWORD SubItems; + const char *pszSuperName = NULL; + HENUMInternal hEnumII; // enumerator for interface impl + mdCustomAttribute *rCA; + ULONG ulCAs; + UINT uImageIndex = CLASS_IMAGE_INDEX; + BOOL bIsEnum = FALSE; + BOOL bIsValueType = FALSE; + BOOL bExtendsSysObject=FALSE; + + if (FAILED(g_pImport->GetNameOfTypeDef( + cl, + &pszClassName, + &pszNamespace))) + { + return FALSE; + } + MAKE_NAME_IF_NONE(pszClassName,cl); + g_pImport->GetTypeDefProps( + cl, + &dwClassAttrs, + &crExtends + ); + if(g_fLimitedVisibility) + { + if(g_fHidePub && (IsTdPublic(dwClassAttrs)||IsTdNestedPublic(dwClassAttrs))) return NULL; + if(g_fHidePriv && (IsTdNotPublic(dwClassAttrs)||IsTdNestedPrivate(dwClassAttrs))) return NULL; + if(g_fHideFam && IsTdNestedFamily(dwClassAttrs)) return NULL; + if(g_fHideAsm && IsTdNestedAssembly(dwClassAttrs)) return NULL; + if(g_fHideFOA && IsTdNestedFamORAssem(dwClassAttrs)) return NULL; + if(g_fHideFAA && IsTdNestedFamANDAssem(dwClassAttrs)) return NULL; + } + hr = g_pImport->EnumInit( + mdtInterfaceImpl, + cl, + &hEnumII); + if (FAILED(hr)) + return FALSE; + + NumInterfaces = g_pImport->EnumGetCount(&hEnumII); + hr = g_pImport->EnumInit(mdtMethodDef, cl, &hEnumMethod); + if (FAILED(hr)) + { + printf("Unable to enum methods\n"); + return FALSE; + } + NumMembers = g_pImport->EnumGetCount(&hEnumMethod); + + hr = g_pImport->EnumInit(mdtFieldDef, cl, &hEnumField); + if (FAILED(hr)) + { + g_pImport->EnumClose(&hEnumMethod); + printf("Unable to enum fields\n"); + return FALSE; + } + NumMembers += g_pImport->EnumGetCount(&hEnumField); + + hr = g_pImport->EnumInit(mdtEvent, cl, &hEnumEvent); + if (FAILED(hr)) + { + g_pImport->EnumClose(&hEnumMethod); + g_pImport->EnumClose(&hEnumField); + printf("Unable to enum events\n"); + return FALSE; + } + NumMembers += g_pImport->EnumGetCount(&hEnumEvent); + + hr = g_pImport->EnumInit(mdtProperty, cl, &hEnumProp); + if (FAILED(hr)) + { + g_pImport->EnumClose(&hEnumMethod); + g_pImport->EnumClose(&hEnumField); + g_pImport->EnumClose(&hEnumEvent); + printf("Unable to enum properties\n"); + return FALSE; + } + NumMembers += g_pImport->EnumGetCount(&hEnumProp); + if (NumMembers > 0) + { + pMemberList = new (nothrow) mdToken[NumMembers]; + if (pMemberList == NULL) + { + // close enum before return + g_pImport->EnumClose(&hEnumMethod); + g_pImport->EnumClose(&hEnumField); + g_pImport->EnumClose(&hEnumEvent); + g_pImport->EnumClose(&hEnumProp); + return FALSE; + } + + for (i = 0; g_pImport->EnumNext(&hEnumField, &pMemberList[i]); i++); + for (; g_pImport->EnumNext(&hEnumMethod, &pMemberList[i]); i++); + for (; g_pImport->EnumNext(&hEnumEvent, &pMemberList[i]); i++); + for (; g_pImport->EnumNext(&hEnumProp, &pMemberList[i]); i++); + _ASSERTE(i == NumMembers); + + } + else + { + pMemberList = NULL; + } + + // Add class root to treeview + SubItems = NumMembers + NumInterfaces + 3; + if (!IsNilToken(crExtends)) + { + LPCSTR szClassName=""; + LPCSTR szNameSpace=""; + SubItems++; + if(TypeFromToken(crExtends)==mdtTypeRef) + { + if (FAILED(g_pImport->GetNameOfTypeRef(crExtends, &szNameSpace, &szClassName))) + { + return FALSE; + } + if(!(strcmp(szNameSpace,"System") || strcmp(szClassName, "Object"))) + { + SubItems--; + bExtendsSysObject = TRUE; + } + } + else if (TypeFromToken(crExtends) == mdtTypeDef) + { + if (FAILED(g_pImport->GetNameOfTypeDef(crExtends, &szClassName, &szNameSpace))) + { + return FALSE; + } + } + + bIsEnum = (!strcmp(szNameSpace,"System"))&&(!strcmp(szClassName,"Enum")); + + bIsValueType = (!strcmp(szNameSpace,"System"))&&(!strcmp(szClassName,"ValueType")) + && (strcmp(pszNamespace,"System") || strcmp(pszClassName,"Enum")); + } + { + HCORENUM hEnum = NULL; + rCA = new (nothrow) mdCustomAttribute[4096]; + g_pPubImport->EnumCustomAttributes(&hEnum, cl, 0, rCA, 4096, &ulCAs); + SubItems += ulCAs; + g_pPubImport->CloseEnum( hEnum); + } + for (i = 0; i < g_NumClasses; i++) + { + if(g_cl_enclosing[i] == cl) SubItems++; + } + + if(IsTdInterface(dwClassAttrs)) uImageIndex = CLASSINT_IMAGE_INDEX; + if(bIsValueType) uImageIndex = CLASSVAL_IMAGE_INDEX; + if(bIsEnum) uImageIndex = CLASSENUM_IMAGE_INDEX; + char *szptr1; + if((*pszNamespace != 0) && g_fTreeViewFCN) + sprintf_s(szString,SZSTRING_SIZE,"%s.",pszNamespace); + else + szString[0] = 0; + strcat_s(szString,SZSTRING_SIZE,pszClassName); + szptr1 = &szString[strlen(szString)]; + // Count the type parameters -- could be too many for GUI + DWORD NumTyPars; + mdGenericParam tkTyPar; + HCORENUM hEnumTyPar = NULL; + unsigned jj; + + for(jj=0; + SUCCEEDED(g_pPubImport->EnumGenericParams(&hEnumTyPar, cl, &tkTyPar, 1, &NumTyPars)) + && (NumTyPars != 0); jj++); + + if (jj > 0) + { + if(jj > 16) + szptr1 += sprintf_s(szptr1,SZSTRING_REMAINING_SIZE(szptr1),"%s%d type parameters%s",LTN(),jj,GTN()); + else + DumpGenericPars(szString,cl); + + uImageIndex = CLASS_GEN_IMAGE_INDEX; + if(IsTdInterface(dwClassAttrs)) uImageIndex = CLASSINT_GEN_IMAGE_INDEX; + if(bIsValueType) uImageIndex = CLASSVAL_GEN_IMAGE_INDEX; + if(bIsEnum) uImageIndex = CLASSENUM_GEN_IMAGE_INDEX; + } + + pClassItem = AddClassToGUI(cl, uImageIndex, pszNamespace, szString, SubItems, &hNamespaceRoot); + if (pClassItem == NULL) + return FALSE; + + hClassRoot = pClassItem->hItem; + + const size_t BUFFER_SIZE = 8192; + szPrimaryInfo = new (nothrow) char[BUFFER_SIZE]; + strcpy_s(szPrimaryInfo, BUFFER_SIZE,".class "); + + if (IsTdInterface(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "interface "); + //else if (IsTdUnmanagedValueType(dwClassAttrs)) strcat(szPrimaryInfo, "not_in_gc_heap value "); + else if (bIsValueType) strcat_s(szPrimaryInfo, BUFFER_SIZE, "value "); + else if (bIsEnum) strcat_s(szPrimaryInfo, BUFFER_SIZE, "enum "); + + if (IsTdPublic(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "public "); + if (IsTdNotPublic(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "private "); + if (IsTdNestedPublic(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "nested public "); + if (IsTdNestedPrivate(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "nested private "); + if (IsTdNestedFamily(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "nested family "); + if (IsTdNestedAssembly(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "nested assembly "); + if (IsTdNestedFamANDAssem(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "nested famandassem "); + if (IsTdNestedFamORAssem(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "nested famorassem "); + if (IsTdAbstract(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "abstract "); + if (IsTdAutoLayout(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "auto "); + if (IsTdSequentialLayout(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "sequential "); + if (IsTdExplicitLayout(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "explicit "); + if (IsTdAnsiClass(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "ansi "); + if (IsTdUnicodeClass(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "unicode "); + if (IsTdAutoClass(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "autochar "); + if (IsTdImport(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "import "); + if (IsTdWindowsRuntime(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "windowsruntime "); + if (IsTdSerializable(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "serializable "); +// if (IsTdEnum(dwClassAttrs)) strcat(szPrimaryInfo, "enum "); + if (IsTdSealed(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "sealed "); + if (IsTdBeforeFieldInit(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "beforefieldinit "); + if (IsTdSpecialName(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "specialname "); + if (IsTdRTSpecialName(dwClassAttrs)) strcat_s(szPrimaryInfo, BUFFER_SIZE, "rtspecialname "); + + if(g_fDumpTokens) sprintf_s(&szPrimaryInfo[strlen(szPrimaryInfo)], BUFFER_SIZE - strlen(szPrimaryInfo)," /*%08X*/",cl); + hPrimaryInfo = AddInfoItemToClass(hClassRoot, pClassItem, szPrimaryInfo, NULL); + hLast = hPrimaryInfo; + // Now add nodes for extends, implements + if (!IsNilToken(crExtends)) + { + if (!bExtendsSysObject) + { + AddClassToTreeView_PrettyPrintClass(crExtends, " extends %s ", szPrimaryInfo, BUFFER_SIZE); + hLast = AddInfoItemToClass(hLast, pClassItem, szPrimaryInfo, crExtends); + } + } + + if (NumInterfaces > 0) + { + for (i=0; g_pImport->EnumNext(&hEnumII, &ii); i++) + { + mdTypeRef crInterface; + + if (FAILED(g_pImport->GetTypeOfInterfaceImpl(ii, &crInterface))) + { + printf("Unable to get information about interface implementation\n"); + return FALSE; + } + { + AddClassToTreeView_PrettyPrintClass(crInterface, " implements %s ", szPrimaryInfo, BUFFER_SIZE); + hLast = AddInfoItemToClass(hLast, pClassItem, szPrimaryInfo, crInterface); + } + } + + // The assertion will fire if the enumerator is bad + _ASSERTE(NumInterfaces == i); + + // close the enumerator + g_pImport->EnumClose(&hEnumII); + } + delete[] szPrimaryInfo; + + BOOL fDumpRTF = g_fDumpRTF; + g_fDumpRTF = FALSE; + // add info entries for custom attributes + for(i = 0; i < ulCAs; i++) + { + char* pc; + memset(GlobalBuffer,0,GlobalBufferLen); + InGlobalBuffer = 0; + DumpCustomAttribute(rCA[i],(void *)g_hwndTreeView,false); + if(pc = strchr(GlobalBuffer,'\r')) strcpy_s(pc,6," ..."); // until the first <CR> only + //hLast = AddInfoItemToClass(hLast, pClassItem, GlobalBuffer, "#####"); // this "name" is guaranteed to be unique! + hLast = AddInfoItemToClass(hLast, pClassItem, GlobalBuffer, rCA[i]); + } + delete[] rCA; + + // Re-fetch the current class item ptr, dynamic array may have shifted + pClassItem = ClassItemByToken(cl); + + // Add nested classes + AddClassesWithEncloser(cl,pClassItem->hItem); + pClassItem = ClassItemByToken(cl); + + MemberInfo* members = NULL; + if (NumMembers != 0) + { + members = new (nothrow) MemberInfo[NumMembers]; + if (members == NULL) + { + if (pMemberList != NULL) delete[] pMemberList; + return FALSE; + } + } + // do in four passes, fields first + MemberInfo* curMem = members; + for (i = 0; i < NumMembers; i++) + { + if (TypeFromToken(pMemberList[i]) == mdtFieldDef) + { + curMem->token = pMemberList[i]; + if (FAILED(g_pImport->GetFieldDefProps(pMemberList[i], &curMem->dwAttrs))) + { + printf("Invalid FieldDef %08X record\n", pMemberList[i]); + delete []members; + delete []pMemberList; + return FALSE; + } + if (FAILED(g_pImport->GetNameOfFieldDef(pMemberList[i], &curMem->pszMemberName))) + { + printf("Invalid FieldDef %08X record\n", pMemberList[i]); + delete []members; + delete []pMemberList; + return FALSE; + } + MAKE_NAME_IF_NONE(curMem->pszMemberName,pMemberList[i]); + if (FAILED(g_pImport->GetSigOfFieldDef(pMemberList[i], &curMem->cComSig, &curMem->pComSig))) + { + printf("Invalid FieldDef %08X record\n", pMemberList[i]); + delete []members; + delete []pMemberList; + return FALSE; + } + curMem++; + } + else break; + } + + MemberInfo* endMem = curMem; + if (g_fSortByName) qsort(members, endMem - members, sizeof MemberInfo, memberCmp); + + for (curMem = members; curMem < endMem;curMem++) + { + if (g_fLimitedVisibility) + { + if(g_fHidePub && IsFdPublic(curMem->dwAttrs)) continue; + if(g_fHidePriv && IsFdPrivate(curMem->dwAttrs)) continue; + if(g_fHideFam && IsFdFamily(curMem->dwAttrs)) continue; + if(g_fHideAsm && IsFdAssembly(curMem->dwAttrs)) continue; + if(g_fHideFOA && IsFdFamORAssem(curMem->dwAttrs)) continue; + if(g_fHideFAA && IsFdFamANDAssem(curMem->dwAttrs)) continue; + if(g_fHidePrivScope && IsFdPrivateScope(curMem->dwAttrs)) continue; + } + AddFieldToGUI(cl, pClassItem, pszNamespace, pszClassName, curMem->pszMemberName, NULL, curMem->token, curMem->dwAttrs); + } + + // methods second + curMem = members; + for (; i < NumMembers; i++) + { + if (TypeFromToken(pMemberList[i]) == mdtMethodDef) + { + curMem->token = pMemberList[i]; + if (FAILED(g_pImport->GetMethodDefProps(pMemberList[i], &curMem->dwAttrs))) + { + printf("Invalid MethodDef %08X record\n", pMemberList[i]); + delete []members; + delete []pMemberList; + return FALSE; + } + + if (FAILED(g_pImport->GetNameOfMethodDef(pMemberList[i], &curMem->pszMemberName))) + { + printf("Invalid MethodDef %08X record\n", pMemberList[i]); + delete []members; + delete []pMemberList; + return FALSE; + } + MAKE_NAME_IF_NONE(curMem->pszMemberName,pMemberList[i]); + if (FAILED(g_pImport->GetSigOfMethodDef(pMemberList[i], &curMem->cComSig, &curMem->pComSig))) + { + printf("Invalid MethodDef %08X record\n", pMemberList[i]); + delete []members; + delete []pMemberList; + return FALSE; + } + curMem++; + } + else break; + } + + endMem = curMem; + if (g_fSortByName) qsort(members, endMem - members, sizeof MemberInfo, memberCmp); + + for (curMem = members; curMem < endMem;curMem++) + { + if (g_fLimitedVisibility) + { + if(g_fHidePub && IsMdPublic(curMem->dwAttrs)) continue; + if(g_fHidePriv && IsMdPrivate(curMem->dwAttrs)) continue; + if(g_fHideFam && IsMdFamily(curMem->dwAttrs)) continue; + if(g_fHideAsm && IsMdAssem(curMem->dwAttrs)) continue; + if(g_fHideAsm && g_fHideFam && IsMdFamORAssem(curMem->dwAttrs)) continue; + if(g_fHideFAA && IsMdFamANDAssem(curMem->dwAttrs)) continue; + if(g_fHidePrivScope && IsMdPrivateScope(curMem->dwAttrs)) continue; + } + AddMethodToGUI(cl, pClassItem, pszNamespace, pszClassName, curMem->pszMemberName, curMem->pComSig, curMem->cComSig, curMem->token, curMem->dwAttrs); + } + // events third + curMem = members; + for (; i < NumMembers; i++) + { + if (TypeFromToken(pMemberList[i]) == mdtEvent) + { + curMem->token = pMemberList[i]; + if (FAILED(g_pImport->GetEventProps( + curMem->token, + &curMem->pszMemberName, + &curMem->dwAttrs, + (mdToken *)&curMem->pComSig))) + { + curMem->pszMemberName = "Invalid Event record"; + curMem->dwAttrs = 0; + curMem->pComSig = (PCCOR_SIGNATURE)mdTypeDefNil; + } + MAKE_NAME_IF_NONE(curMem->pszMemberName,pMemberList[i]); + curMem++; + } + else break; + } + + endMem = curMem; + if (g_fSortByName) qsort(members, endMem - members, sizeof MemberInfo, memberCmp); + curMem = members; + while (curMem < endMem) + { + if (g_fLimitedVisibility) + { + HENUMInternal hAssoc; + unsigned nAssoc; + if (FAILED(g_pImport->EnumAssociateInit(curMem->token,&hAssoc))) + { + continue; + } + if (nAssoc = hAssoc.m_ulCount) + { + NewArrayHolder<ASSOCIATE_RECORD> rAssoc = new (nothrow) ASSOCIATE_RECORD[nAssoc]; + if (FAILED(g_pImport->GetAllAssociates(&hAssoc,rAssoc,nAssoc))) + { + continue; + } + + for (unsigned i=0; i < nAssoc;i++) + { + if (TypeFromToken(rAssoc[i].m_memberdef) == mdtMethodDef) + { + DWORD dwAttrs; + if (FAILED(g_pImport->GetMethodDefProps(rAssoc[i].m_memberdef, &dwAttrs))) + { + continue; + } + if(g_fHidePub && IsMdPublic(dwAttrs)) continue; + if(g_fHidePriv && IsMdPrivate(dwAttrs)) continue; + if(g_fHideFam && IsMdFamily(dwAttrs)) continue; + if(g_fHideAsm && IsMdAssem(dwAttrs)) continue; + if(g_fHideFOA && IsMdFamORAssem(dwAttrs)) continue; + if(g_fHideFAA && IsMdFamANDAssem(dwAttrs)) continue; + if(g_fHidePrivScope && IsMdPrivateScope(dwAttrs)) continue; + } + AddEventToGUI(cl, pClassItem, pszNamespace, pszClassName, dwClassAttrs, curMem->token); + break; + } + } + g_pImport->EnumClose(&hAssoc); + } + else AddEventToGUI(cl, pClassItem, pszNamespace, pszClassName, dwClassAttrs, curMem->token); + curMem++; + } + // properties fourth + curMem = members; + for (; i < NumMembers; i++) + { + if (TypeFromToken(pMemberList[i]) == mdtProperty) + { + curMem->token = pMemberList[i]; + if (FAILED(g_pImport->GetPropertyProps( + curMem->token, + &curMem->pszMemberName, + &curMem->dwAttrs, + &curMem->pComSig, + &curMem->cComSig))) + { + curMem->pszMemberName = "Invalid Property record"; + curMem->dwAttrs = 0; + curMem->pComSig = NULL; + curMem->cComSig = 0; + } + MAKE_NAME_IF_NONE(curMem->pszMemberName,pMemberList[i]); + curMem++; + } + } + + endMem = curMem; + if(g_fSortByName) qsort(members, endMem - members, sizeof MemberInfo, memberCmp); + curMem = members; + while(curMem < endMem) + { + if (g_fLimitedVisibility) + { + HENUMInternal hAssoc; + unsigned nAssoc; + if (FAILED(g_pImport->EnumAssociateInit(curMem->token,&hAssoc))) + { + continue; + } + if (nAssoc = hAssoc.m_ulCount) + { + NewArrayHolder<ASSOCIATE_RECORD> rAssoc = new (nothrow) ASSOCIATE_RECORD[nAssoc]; + if (FAILED(g_pImport->GetAllAssociates(&hAssoc,rAssoc,nAssoc))) + { + continue; + } + + for (unsigned i=0; i < nAssoc;i++) + { + if (TypeFromToken(rAssoc[i].m_memberdef) == mdtMethodDef) + { + DWORD dwAttrs; + if (FAILED(g_pImport->GetMethodDefProps(rAssoc[i].m_memberdef, &dwAttrs))) + { + continue; + } + if(g_fHidePub && IsMdPublic(dwAttrs)) continue; + if(g_fHidePriv && IsMdPrivate(dwAttrs)) continue; + if(g_fHideFam && IsMdFamily(dwAttrs)) continue; + if(g_fHideAsm && IsMdAssem(dwAttrs)) continue; + if(g_fHideFOA && IsMdFamORAssem(dwAttrs)) continue; + if(g_fHideFAA && IsMdFamANDAssem(dwAttrs)) continue; + if(g_fHidePrivScope && IsMdPrivateScope(dwAttrs)) continue; + } + AddPropToGUI(cl, pClassItem, pszNamespace, pszClassName, dwClassAttrs, curMem->token); + break; + } + } + g_pImport->EnumClose(&hAssoc); + } + else AddPropToGUI(cl, pClassItem, pszNamespace, pszClassName, dwClassAttrs, curMem->token); + curMem++; + } + g_fDumpRTF = fDumpRTF; + if(pMemberList) delete[] pMemberList; + if(members) delete[] members; +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + return hClassRoot; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + +void CreateMenus() +{ + HMENU hMenuPopup; + + g_hMenu = CreateMenu(); + + hMenuPopup = CreateMenu(); + WszAppendMenu(hMenuPopup, MF_STRING, IDM_OPEN, RstrW(IDS_OPEN)); + WszAppendMenu(hMenuPopup, MF_STRING|MF_GRAYED, IDM_DUMP, RstrW(IDS_DUMP)); + WszAppendMenu(hMenuPopup, MF_STRING|MF_GRAYED, IDM_DUMP_TREE, RstrW(IDS_DUMPTREE)); + WszAppendMenu(hMenuPopup, MF_STRING, IDM_EXIT, RstrW(IDS_EXIT)); + WszAppendMenu(g_hMenu, MF_POPUP, (UINT)(UINT_PTR)hMenuPopup, RstrW(IDS_FILE)); + g_hFileMenu = hMenuPopup; + + hMenuPopup = CreateMenu(); + g_hFontMenu = CreateMenu(); + WszAppendMenu(hMenuPopup,MF_POPUP,(UINT)(UINT_PTR)g_hFontMenu,RstrW(IDS_FONTS)); + WszAppendMenu(g_hFontMenu,MF_STRING,IDM_FONT_TREE,RstrW(IDS_FONT_TREE)); + WszAppendMenu(g_hFontMenu,MF_STRING,IDM_FONT_DASM,RstrW(IDS_FONT_DASM)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fSortByName ? MF_CHECKED : MF_UNCHECKED), IDM_SORT_BY_NAME, RstrW(IDS_SORT_BY_NAME)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fTreeViewFCN ? MF_CHECKED : MF_UNCHECKED), IDM_TREEVIEWFCN, RstrW(IDS_TREEVIEWFCN)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fCAVerbal ? MF_CHECKED : MF_UNCHECKED), IDM_CAVERBAL, RstrW(IDS_CAVERBAL)); + //WszAppendMenu(hMenuPopup, MF_STRING|(g_fDumpRTF ? MF_CHECKED : MF_UNCHECKED), IDM_DUMPRTF, RstrW(IDS_DUMPRTF)); + // MF_SEPARATOR ==> last 2 params ignored + WszAppendMenu(hMenuPopup, MF_SEPARATOR,0,NULL); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fHidePub ? MF_CHECKED : MF_UNCHECKED), IDM_SHOW_PUB, RstrW(IDS_SHOW_PUB)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fHidePriv ? MF_CHECKED : MF_UNCHECKED), IDM_SHOW_PRIV, RstrW(IDS_SHOW_PRIV)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fHideFam ? MF_CHECKED : MF_UNCHECKED), IDM_SHOW_FAM, RstrW(IDS_SHOW_FAM)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fHideAsm ? MF_CHECKED : MF_UNCHECKED), IDM_SHOW_ASM, RstrW(IDS_SHOW_ASM)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fHideFAA ? MF_CHECKED : MF_UNCHECKED), IDM_SHOW_FAA, RstrW(IDS_SHOW_FAA)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fHideFOA ? MF_CHECKED : MF_UNCHECKED), IDM_SHOW_FOA, RstrW(IDS_SHOW_FOA)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fHidePrivScope ? MF_CHECKED : MF_UNCHECKED), IDM_SHOW_PSCOPE, RstrW(IDS_SHOW_PSCOPE)); + WszAppendMenu(hMenuPopup, MF_SEPARATOR,0,NULL); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fFullMemberInfo ? MF_CHECKED : MF_UNCHECKED), IDM_FULL_INFO, RstrW(IDS_FULL_INFO)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fShowBytes ? MF_CHECKED : MF_UNCHECKED), IDM_BYTES, RstrW(IDS_BYTES)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fDumpTokens ? MF_CHECKED : MF_UNCHECKED), IDM_TOKENS, RstrW(IDS_TOKENS)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fShowSource ? MF_CHECKED : MF_UNCHECKED), IDM_SOURCELINES, RstrW(IDS_SOURCELINES)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fQuoteAllNames ? MF_CHECKED : MF_UNCHECKED), IDM_QUOTEALLNAMES, RstrW(IDS_QUOTEALLNAMES)); + WszAppendMenu(hMenuPopup, MF_STRING|(g_fTryInCode ? MF_CHECKED : MF_UNCHECKED), IDM_EXPANDTRY, RstrW(IDS_EXPANDTRY)); + if(g_fTDC) + { + + WszAppendMenu(hMenuPopup, MF_STRING, IDM_SHOW_HEADER, RstrW(IDS_SHOW_HEADER)); + WszAppendMenu(hMenuPopup, MF_STRING, IDM_SHOW_STAT, RstrW(IDS_SHOW_STAT)); + g_hMetaInfoMenu = CreateMenu(); + //MENUINFO mi; + //GetMenuInfo(g_hMetaInfoMenu,&mi); + //mi.dwStyle |= MNS_MODELESS; + //SetMenuInfo(g_hMetaInfoMenu,&mi); + WszAppendMenu(hMenuPopup, MF_POPUP, (UINT)(UINT_PTR)g_hMetaInfoMenu, RstrW(IDS_METAINFO)); + + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpMoreHex ? MF_CHECKED : MF_UNCHECKED),IDM_MI_HEX,RstrW(IDS_MI_HEX)); + WszAppendMenu(g_hMetaInfoMenu,MF_SEPARATOR,0,NULL); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpCSV ? MF_CHECKED : MF_UNCHECKED),IDM_MI_CSV,RstrW(IDS_MI_CSV)); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpHeader ? MF_CHECKED : MF_UNCHECKED),IDM_MI_HEADER,RstrW(IDS_MI_HEADER)); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpSchema ? MF_CHECKED : MF_UNCHECKED),IDM_MI_SCHEMA,RstrW(IDS_MI_SCHEMA)); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpRaw ? MF_CHECKED : MF_UNCHECKED),IDM_MI_RAW,RstrW(IDS_MI_RAW)); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpRawHeaps ? MF_CHECKED : MF_UNCHECKED),IDM_MI_HEAPS,RstrW(IDS_MI_HEAPS)); + WszAppendMenu(g_hMetaInfoMenu,MF_SEPARATOR,0,NULL); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpUnsat ? MF_CHECKED : MF_UNCHECKED),IDM_MI_UNREX,RstrW(IDS_MI_UNREX)); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING|(g_ulMetaInfoFilter & MDInfo::dumpValidate ? MF_CHECKED : MF_UNCHECKED),IDM_MI_VALIDATE,RstrW(IDS_MI_VALIDATE)); + WszAppendMenu(g_hMetaInfoMenu,MF_STRING,IDM_SHOW_METAINFO,RstrW(IDS_SHOW_METAINFO)); + } + WszAppendMenu(g_hMenu, MF_POPUP|MF_GRAYED, (UINT)(UINT_PTR)hMenuPopup, RstrW(IDS_VIEW)); + g_hViewMenu = hMenuPopup; + hMenuPopup = CreateMenu(); + WszAppendMenu(hMenuPopup, MF_STRING, IDM_HELP,RstrW(IDS_HELP)); + WszAppendMenu(hMenuPopup, MF_STRING, IDM_ABOUT,RstrW(IDS_ABOUT)); + WszAppendMenu(g_hMenu, MF_POPUP, (UINT)(UINT_PTR)hMenuPopup, RstrW(IDS_HELP)); +} + +BOOL LoadImages() +{ + int i; + + g_hImageList = ImageList_Create(BITMAP_WIDTH, BITMAP_HEIGHT, ILC_COLOR8, LAST_IMAGE_INDEX, 1); + if (g_hImageList == NULL) + return FALSE; + + _ASSERTE(g_hResources != NULL); + for (i = 0; i < LAST_IMAGE_INDEX; i++) + { + g_hBitmaps[i] = (HBITMAP) WszLoadImage( + g_hResources, + MAKEINTRESOURCE(i + IDB_CLASS), + IMAGE_BITMAP, + 15, + 15, + LR_LOADTRANSPARENT //LR_DEFAULTCOLOR + ); + if (g_hBitmaps[i] == NULL) + return FALSE; + int index = ImageList_Add(g_hImageList, g_hBitmaps[i], NULL); + if (index != i) + return FALSE; + } + + return TRUE; +} +// Local functions for font persistence: +char* FontSaveFileName() +{ + static char szFileName[MAX_PATH]; + static BOOL bInit = TRUE; + if(bInit) + { + (void)GetWindowsDirectoryA(szFileName,MAX_PATH); + if(szFileName[strlen(szFileName)-1]!='\\') strcat_s(szFileName,MAX_PATH,"\\"); + strcat_s(szFileName,MAX_PATH,"ildasmfnt.bin"); + bInit = FALSE; + } + return szFileName; +} +BOOL LoadGUIFonts(GUI_Info* pguiInfo) +{ + FILE* pF = NULL; + BOOL ret = FALSE; + int dummy; + if(fopen_s(&pF,FontSaveFileName(),"rb")==0) + { + ret = (fread(pguiInfo->plfDasm,sizeof(LOGFONTW),1,pF) && fread(pguiInfo->plfTree,sizeof(LOGFONTW),1,pF)); + if(fread(&dummy,sizeof(int),1,pF)) pguiInfo->x = dummy; + if(fread(&dummy,sizeof(int),1,pF)) pguiInfo->y = dummy; + if(fread(&dummy,sizeof(int),1,pF)) pguiInfo->w = dummy; + if(fread(&dummy,sizeof(int),1,pF)) pguiInfo->h = dummy; + if(fread(&dummy,sizeof(int),1,pF)) g_fTreeViewFCN = (dummy != 0); + if(fread(&dummy,sizeof(int),1,pF)) g_fSortByName = (dummy != 0); + if(fread(&dummy,sizeof(int),1,pF)) g_fFullMemberInfo = (dummy != 0); + + fclose(pF); + } + return ret; +} +BOOL SaveGUIFonts(GUI_Info* pguiInfo) +{ + FILE* pF=NULL; + BOOL ret = FALSE; + int dummyFCN = (g_fTreeViewFCN ? 1:0); + int dummySBN = (g_fSortByName ? 1:0); + int dummyFMI = (g_fFullMemberInfo ? 1:0); + if(fopen_s(&pF,FontSaveFileName(),"wb")==0) + { + ret = (fwrite(pguiInfo->plfDasm,sizeof(LOGFONTW),1,pF) + && fwrite(pguiInfo->plfTree,sizeof(LOGFONTW),1,pF) + && fwrite(&(pguiInfo->x),sizeof(int),1,pF) + && fwrite(&(pguiInfo->y),sizeof(int),1,pF) + && fwrite(&(pguiInfo->w),sizeof(int),1,pF) + && fwrite(&(pguiInfo->h),sizeof(int),1,pF) + && fwrite(&dummyFCN,sizeof(int),1,pF) + && fwrite(&dummySBN,sizeof(int),1,pF) + && fwrite(&dummyFMI,sizeof(int),1,pF) + ); + fclose(pF); + } + return ret; +} +// Init various GUI variables, get handles +// if InitGUI returns FALSE, ildasm exits +#define DEFAULT_FONTS +BOOL InitGUI() +{ + INITCOMMONCONTROLSEX InitInfo; +#ifdef DEFAULT_FONTS + LOGFONTW strDefaultLogFontDasm = {-14,0,0,0,FW_REGULAR,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,FIXED_PITCH | FF_MODERN,L"Fixedsys"}; + LOGFONTW strDefaultLogFontTree = {-11,0,0,0,FW_REGULAR,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,VARIABLE_PITCH | FF_SWISS,L"Tahoma"}; + LOGFONTA strDefaultLogFontDasmA = {-14,0,0,0,FW_REGULAR,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,FIXED_PITCH | FF_MODERN,"Fixedsys"}; + LOGFONTA strDefaultLogFontTreeA = {-11,0,0,0,FW_REGULAR,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,VARIABLE_PITCH | FF_SWISS,"Tahoma"}; +#endif + g_DisasmBox = new DynamicArray<DisasmBox_t>; + g_ClassItemList = new DynamicArray<ClassItem_t>; + g_NamespaceList = new DynamicArray<Namespace_t>; + WszLoadLibrary(L"riched20.dll"); + + InitInfo.dwSize = sizeof(InitInfo); + InitInfo.dwICC = ICC_LISTVIEW_CLASSES; + + if (InitCommonControlsEx(&InitInfo) == FALSE) + return FALSE; + + g_hInstance = WszGetModuleHandle(NULL); + g_hResources = LoadLocalizedResourceDLLForSDK(L"ildasmrc.dll"); + + //--------- get logical fonts +#ifdef DEFAULT_FONTS + if(!LoadGUIFonts(&guiInfo)) + { + memcpy(&g_strLogFontDasm,&strDefaultLogFontDasm,sizeof(LOGFONTW)); + memcpy(&g_strLogFontTree,&strDefaultLogFontTree,sizeof(LOGFONTW)); + } + if(g_fDumpRTF) { g_strLogFontDasm.lfWeight = FW_REGULAR; g_strLogFontDasm.lfItalic = FALSE; } + // -------- create font for disassembly window + g_hFixedFont = CreateFontIndirectW(&g_strLogFontDasm); + // -------- create font for tree view + g_hSmallFont = CreateFontIndirectW(&g_strLogFontTree); +#else + if(LoadGUIFonts(&guiInfo)) + { + if(g_fDumpRTF) { g_strLogFontDasm.lfWeight = FW_REGULAR; g_strLogFontDasm.lfItalic = FALSE; } + // -------- create font for disassembly window + g_hFixedFont = CreateFontIndirect(&g_strLogFontDasm); + // -------- create font for tree view + g_hSmallFont = CreateFontIndirect(&g_strLogFontTree); + } + else + { + g_hFixedFont = (HFONT)GetStockObject(SYSTEM_FIXED_FONT); + g_hSmallFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + } +#endif + if (g_hFixedFont == NULL) return FALSE; + if (g_hSmallFont == NULL) return FALSE; + + memset(&g_strChFontDasm,0,sizeof(CHOOSEFONT)); + g_strChFontDasm.lStructSize = sizeof(CHOOSEFONT); + g_strChFontDasm.lpLogFont = &g_strLogFontDasm; + g_strChFontDasm.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS |CF_SHOWHELP; + if(!g_fDumpRTF) g_strChFontDasm.Flags |= CF_EFFECTS; // no color change option for RTF output! + g_strChFontDasm.rgbColors = GetSysColor(COLOR_INFOTEXT); + + memset(&g_strChFontTree,0,sizeof(CHOOSEFONTW)); + g_strChFontTree.lStructSize = sizeof(CHOOSEFONTW); + g_strChFontTree.lpLogFont = &g_strLogFontTree; + g_strChFontTree.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS |CF_SHOWHELP /*| CF_EFFECTS*/; + g_strChFontTree.rgbColors = GetSysColor(COLOR_WINDOWTEXT); + + g_hWhiteBrush = (HBRUSH) GetStockObject(WHITE_BRUSH); + if (g_hWhiteBrush == NULL) + return FALSE; + + if (LoadImages() == FALSE) + return FALSE; + + if (RegisterWindowClasses() == FALSE) + return FALSE; +#undef RegisterWindowMessageW + g_uFindReplaceMsg = RegisterWindowMessageW(FINDMSGSTRING); + + CreateMenus(); + + return TRUE; +} + +void DestroyGUI() +{ + SDELETE(g_DisasmBox); + SDELETE(g_ClassItemList); + SDELETE(g_NamespaceList); +} +// +// Set the font of a particular window to the global fixed size font +// +void SetWindowFontFixed(HWND hwnd) +{ + WszSendMessage( + hwnd, + WM_SETFONT, + (LPARAM) g_hFixedFont, + FALSE + ); +} + + +// +// Set the char dimensions variables +// +void SetCharDimensions(HWND hwnd) +{ + if (InterlockedIncrement(&g_SetCharDimensions) == 1) + { + HDC hdc; + TEXTMETRIC tm; + + hdc = GetDC(hwnd); + + GetTextMetrics(hdc, &tm); + + g_MaxCharWidth = tm.tmAveCharWidth; + g_Height = tm.tmHeight; + + ReleaseDC(hwnd, hdc); + } + else + { + // Already set + InterlockedDecrement(&g_SetCharDimensions); + } +} + + +// +// Given a member handle and a class item, find the TreeItem for that member +// +TreeItem_t *FindMemberInClass(ClassItem_t *pClassItem, HTREEITEM hMember) +{ + DWORD i; + + for (i = 0; i < pClassItem->SubItems; i++) + { + if (pClassItem->pMembers[i].hItem == hMember) + return &pClassItem->pMembers[i]; + } + + return NULL; +} + + +// +// Register the window classes +// +BOOL RegisterWindowClasses() +{ + _ASSERTE(g_hResources != NULL); + WNDCLASSW wndClass; + + wndClass.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW; + wndClass.lpfnWndProc = DisassemblyWndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = g_hInstance; + wndClass.hIcon = WszLoadIcon(g_hResources,MAKEINTRESOURCE(IDI_ICON2)); + wndClass.hCursor = NULL; + wndClass.hbrBackground = g_hWhiteBrush; + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = DISASSEMBLY_CLASS_NAMEW; + if (WszRegisterClass((WNDCLASSW*)(&wndClass)) == 0) + return FALSE; + + wndClass.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW; + wndClass.lpfnWndProc = MainWndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = g_hInstance; + wndClass.hIcon = WszLoadIcon(g_hResources,MAKEINTRESOURCE(IDI_ICON2)); + wndClass.hCursor = NULL; + wndClass.hbrBackground = g_hWhiteBrush; + wndClass.lpszMenuName = NULL; + + wndClass.lpszClassName = MAIN_WINDOW_CLASSW; + if (WszRegisterClass((WNDCLASSW*)(&wndClass)) == 0) + return FALSE; + return TRUE; +} + +// +// Dump one item to global buffer +// +void GUIDumpItemToDisassemblyEditBox(void*pvDLB, mdToken cl, mdToken mbMember) +{ + const char * pszClassName; + const char * pszNamespace; + mdTypeRef crExtends; + DWORD dwClassAttrs; + + if ((cl != mdTokenNil)&&TypeFromToken(mbMember)) + { + if (FAILED(g_pImport->GetNameOfTypeDef(cl, &pszClassName, &pszNamespace))) + { + pszClassName = pszNamespace = "Invalid TypeDef record"; + } + MAKE_NAME_IF_NONE(pszClassName,cl); + } + else + { + pszClassName = (TypeFromToken(mbMember) == mdtMethodDef) ? "Global Functions" : "Global Fields"; + } + memset(GlobalBuffer,0,GlobalBufferLen); + InGlobalBuffer = 0; + + if (TypeFromToken(mbMember) && cl && (cl != mdTypeDefNil)) + { + if (FAILED(g_pImport->GetTypeDefProps(cl, &dwClassAttrs, &crExtends))) + { + dwClassAttrs = 0; + crExtends = mdTypeDefNil; + } + } + g_Mode |= MODE_GUI; + //_ASSERTE(0); + mdToken tkVarOwner = g_tkVarOwner; + g_tkVarOwner = cl; + if(g_fDumpRTF) DumpRTFPrefix(pvDLB,FALSE); + switch (TypeFromToken(mbMember)) + { + case 0: + switch(cl) + { + case 0: + DumpManifest(pvDLB); + DumpTypedefs(pvDLB); + break; + case IDM_SHOW_HEADER: + DumpHeader(g_CORHeader,pvDLB); + DumpHeaderDetails(g_CORHeader,pvDLB); + break; + case IDM_SHOW_METAINFO: + DumpMetaInfo(g_wszFullInputFile,NULL,pvDLB); + break; + case IDM_SHOW_STAT: + DumpStatistics(g_CORHeader,pvDLB); + break; + } + break; + + case mdtTypeDef: + DumpClass(mbMember,VAL32(g_CORHeader->EntryPointToken), pvDLB, 1); //1 = title+size+pack+custom attributes + break; + case mdtFieldDef: + { + ULONG ul1,ul2; + GetClassLayout(cl,&ul1,&ul2); + DumpField(mbMember,pszClassName, pvDLB, TRUE); + } + break; + case mdtMethodDef: + DumpMethod(mbMember,pszClassName,VAL32(g_CORHeader->EntryPointToken), pvDLB, TRUE); + break; + case mdtEvent: + DumpEvent(mbMember,pszClassName, dwClassAttrs, pvDLB, TRUE); + break; + case mdtProperty: + DumpProp(mbMember,pszClassName, dwClassAttrs, pvDLB, TRUE); + break; + } + if(g_fDumpRTF) DumpRTFPostfix(pvDLB); + g_tkVarOwner = tkVarOwner; + if(g_uCodePage==0xFFFFFFFF) + { + SendMessageW((HWND)pvDLB,WM_SETTEXT,0, (LPARAM)GlobalBuffer); + } + else + { + UINT32 L = (UINT32)strlen(GlobalBuffer); + WCHAR* wz = new (nothrow) WCHAR[L+4]; + if(wz) + { + memset(wz,0,sizeof(WCHAR)*(L+2)); + int x = WszMultiByteToWideChar(CP_UTF8,0,GlobalBuffer,-1,wz,L+2); + if(g_fDumpRTF) + { + x = (int)SendMessageA((HWND)pvDLB,WM_SETTEXT,0, (LPARAM)UnicodeToAnsi(wz)); + } + else + { + SETTEXTEX ste; + ste.flags = ST_DEFAULT; + ste.codepage = 1200; + x = (int)WszSendMessage((HWND)pvDLB,EM_SETTEXTEX,(WPARAM)&ste, (LPARAM)wz); + } + delete[] wz; + } + } +} + +// +// Disassemble the given method in a new window +// + +HWND GUIDisassemble(mdTypeDef cl, mdToken mbMember, __in __nullterminated char *pszNiceMemberName) +{ + HWND hwndDisassemblyMain; + HWND hwndDisassemblyListBox; + const char * pszClassName; + const char * pszNamespace; + char* szTemp=NULL; + RECT rcl; + static char szsz[4096]; + bool fUpdate = false; + bool fMetaInfo = (TypeFromToken(mbMember)==0)&&(cl==IDM_SHOW_METAINFO); + BOOL fDumpRTF = g_fDumpRTF; + if(fMetaInfo) g_fDumpRTF = FALSE; + + //before we even try, check if this member's disasm box is already opened + DisasmBox_t* pDisasmBox = FindDisasmBox(cl, mbMember); + if(pDisasmBox) + { + if(fMetaInfo || (0 == strcmp(pszNiceMemberName,"UpdateThisDisassemblyBox"))) + { + fUpdate = true; + } + else + { + PostMessageA(pDisasmBox->hwndContainer,WM_ACTIVATE,WA_CLICKACTIVE,0); + PostMessageA(pDisasmBox->hwndContainer,WM_SETFOCUS,0,0); + return pDisasmBox->hwndContainer; + } + } + if(fUpdate) + { + SendMessageW(pDisasmBox->hwndContainer,WM_GETTEXT, 0, (LPARAM)szsz); + strcpy_s(szsz,4096,UnicodeToUtf((WCHAR*)szsz)); + + szTemp = szsz; + PostMessageA(pDisasmBox->hwndContainer,WM_CLOSE,1,0); + } + else + { + // Prepend class name to nicely formatted member name + if (mbMember != 0) + { + if (cl != mdTokenNil) + { + if (FAILED(g_pImport->GetNameOfTypeDef( + cl, + &pszClassName, + &pszNamespace))) + { + pszClassName = pszNamespace = "Invalid TypeDef record"; + } + MAKE_NAME_IF_NONE(pszClassName,cl); + if(*pszNamespace != 0) + sprintf_s(szsz,4096,"%s.",pszNamespace); + else + szsz[0] = 0; + strcat_s(szsz,4096,pszClassName); + pszClassName = (const char*)&szsz[0]; + } + else + { + pszClassName = (TypeFromToken(mbMember) == mdtMethodDef) ? "Global Functions" : "Global Fields"; + } + szTemp = new (nothrow) char[strlen(pszClassName)+strlen(pszNiceMemberName)+4]; + if(szTemp) sprintf_s(szTemp, strlen(pszClassName)+strlen(pszNiceMemberName)+4,"%s::%s", pszClassName, pszNiceMemberName); + _ASSERTE(TypeFromToken(mbMember) & (mdtMethodDef|mdtEvent|mdtProperty|mdtTypeDef|mdtFieldDef)); + } + if(!szTemp) szTemp = pszNiceMemberName; + } + _ASSERTE(szTemp); + + HMENU hMenu = CreateMenu(); + WszAppendMenu(hMenu, MF_STRING, IDM_FIND, RstrW(IDS_FIND)); + WszAppendMenu(hMenu, MF_STRING, IDM_FINDNEXT, RstrW(IDS_FINDNEXT)); + + hwndDisassemblyMain = WszCreateWindowEx( + WS_EX_CLIENTEDGE, + DISASSEMBLY_CLASS_NAMEW, + UtfToUnicode(szTemp), + WS_OVERLAPPEDWINDOW | WS_SIZEBOX, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 400, + NULL, + hMenu, // menu + g_hInstance, // hinst + NULL + ); + SendMessageW(hwndDisassemblyMain,WM_SETTEXT, 0, (LPARAM)(UtfToUnicode(szTemp))); + + if((!fUpdate) && szTemp &&(szTemp != pszNiceMemberName)) delete[] szTemp; + if (hwndDisassemblyMain == NULL) + { + g_fDumpRTF = fDumpRTF; + return NULL; + } + GetClientRect(hwndDisassemblyMain, &rcl); + + hwndDisassemblyListBox = WszCreateWindowEx( + 0, + (!g_fDumpRTF) ? L"RichEdit20W" : L"RichEdit20A", + RstrW(IDS_TEXTTOOLARGEFORGUI), + WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE + | ES_MULTILINE | ES_READONLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_NOHIDESEL, + rcl.left, + rcl.top, + rcl.right - rcl.left, + rcl.bottom - rcl.top, + hwndDisassemblyMain, + (HMENU) ID_LISTBOX, + g_hInstance, // hinst + NULL + ); + + DWORD e = GetLastError(); + _ASSERTE(hwndDisassemblyListBox); + if (hwndDisassemblyListBox == NULL) + { + DestroyWindow(hwndDisassemblyMain); + return NULL; + } + + if(fUpdate) + { + UpdateDisasmBox(pDisasmBox, hwndDisassemblyMain, hwndDisassemblyListBox, hMenu); + } + else + AddDisasmBox(hwndDisassemblyMain, hwndDisassemblyListBox, hMenu, cl, mbMember); + + SendMessage(hwndDisassemblyListBox,EM_SETTEXTMODE,TM_RICHTEXT|TM_MULTICODEPAGE,0); + SendMessage(hwndDisassemblyListBox,EM_SETBKGNDCOLOR,0,GetSysColor(COLOR_INFOBK)); + SetWindowFontFixed(hwndDisassemblyListBox); + SetCharDimensions(hwndDisassemblyListBox); + + GUIDumpItemToDisassemblyEditBox((void *)hwndDisassemblyListBox,cl,mbMember); + + ShowWindow(hwndDisassemblyMain, SW_SHOWNORMAL); + UpdateWindow(hwndDisassemblyMain); + + g_fDumpRTF = fDumpRTF; + return hwndDisassemblyMain; +} + +// +// Callback by the disassembler to add another entry to the disassembly window +// +void GUIAddOpcode(__inout_opt __nullterminated const char *pszString, __in_opt void *GUICookie) +{ + if(pszString) + { + ULONG L = (g_uCodePage == 0xFFFFFFFF) ? (ULONG)(wcslen((WCHAR*)pszString)*sizeof(WCHAR)) : (ULONG)strlen(pszString); + if(InGlobalBuffer+L >= GlobalBufferLen-4) + { + ULONG LL = ((L >> 12)+1)<<12; + char *pch = new (nothrow) char[GlobalBufferLen + LL]; + if(pch) + { + memcpy(pch,GlobalBuffer,InGlobalBuffer+1); + delete[] GlobalBuffer; + GlobalBuffer = pch; + GlobalBufferLen += LL; + } + } + if(g_uCodePage == 0xFFFFFFFF) + { + if(g_fDumpRTF) + { + swprintf_s((WCHAR*)&GlobalBuffer[InGlobalBuffer], (GlobalBufferLen-InGlobalBuffer)/sizeof(WCHAR), L"%s\\line\r\n",(WCHAR*)pszString); + InGlobalBuffer += L+14; + } + else + { + swprintf_s((WCHAR*)&GlobalBuffer[InGlobalBuffer], (GlobalBufferLen-InGlobalBuffer)/sizeof(WCHAR), L"%s\r\n",(WCHAR*)pszString); + InGlobalBuffer += L+4; + } + } + else + { + if(g_fDumpRTF) + { + sprintf_s(&GlobalBuffer[InGlobalBuffer],GlobalBufferLen-InGlobalBuffer,"%s\\line\r\n",pszString); + InGlobalBuffer += L+7; + } + else + { + sprintf_s(&GlobalBuffer[InGlobalBuffer],GlobalBufferLen-InGlobalBuffer,"%s\r\n",pszString); + InGlobalBuffer += L+2; + } + } + } + else + { + delete[] GlobalBuffer; + GlobalBufferLen = 0; + InGlobalBuffer = 0; + } +} + +// +// Someone has double clicked on an item +// +// It could be a method (diassemble it), or a field (ignore it), or an "extends" or "implements" +// component, in which case we select that component if available. +// +HWND DoubleClickSelectedMember(HTREEITEM hItem) +{ + HTREEITEM hClass; + ClassItem_t *pClassItem; + + static HCURSOR hWaitCursor = NULL; + + if (hWaitCursor == NULL) + hWaitCursor = WszLoadCursor(NULL,IDC_WAIT); + + // + // It could be any item, but assume it's a member item or class info and find its parent + // + hClass = TreeView_GetParent(g_hwndTreeView, hItem); + if (hClass == NULL) + return NULL; + + // + // Find the class item given the HTREEITEM + // (will return NULL if hClass is not really a class item) + // + pClassItem = FindClassItem(hClass); + if (pClassItem != NULL) + { + // Which subitem was it? + TreeItem_t *pItem = FindMemberInClass(pClassItem, hItem); + + if (pItem == NULL) + return NULL; + + if (pItem->Discriminator == TREEITEM_TYPE_MEMBER) + { + TVITEMA SelItem; + char* szText; + // Must be a method, event or property + switch (TypeFromToken(pItem->mbMember)) + { + case mdtMethodDef: + case mdtEvent: + case mdtProperty: + case mdtFieldDef: + break; + default: + return NULL; + } + + + // Get the name of this item so that we can title the disassembly window + szText = new (nothrow) char[8192]; + if(szText) + { + memset(&SelItem, 0, sizeof(SelItem)); + SelItem.mask = TVIF_TEXT; + SelItem.pszText = szText; + SelItem.hItem = pItem->hItem; + SelItem.cchTextMax = 8192; + + WCHAR* wzText = (WCHAR*)szText; + SelItem.cchTextMax /= sizeof(WCHAR); + SendMessageW(g_hwndTreeView, TVM_GETITEMW, 0, (LPARAM) (LPTVITEMW) &SelItem); + unsigned L = ((unsigned)wcslen(wzText)+1)*3; + char* szUTFText = new (nothrow) char[L]; + if(szUTFText) + { + memset(szUTFText,0,L); + WszWideCharToMultiByte(CP_UTF8,0,wzText,-1,szUTFText,L,NULL,NULL); + delete[] wzText; + szText = szUTFText; + } + } + HCURSOR hWasCursor = SetCursor(hWaitCursor); + + HWND hRet = GUIDisassemble(pClassItem->cl, pItem->mbMember, szText? szText : ""); + if(szText) delete[] szText; + + SetCursor(hWasCursor); + + return hRet; + } + else if (pItem->Discriminator == TREEITEM_TYPE_INFO) + { + if(pItem->mbMember) + { + if(pItem->mbMember != 0xFFFFFFFF) + { + // We've clicked on an "extends X" or "implements Y", so select that class + SelectClassByToken(pItem->mbMember); + } + else + { + HCURSOR hWasCursor = SetCursor(hWaitCursor); + + HWND hRet = GUIDisassemble(0, 0, "MANIFEST"); + + SetCursor(hWasCursor); + return hRet; + } + } + else + { + TVITEMA SelItem; + char* szText = new (nothrow) char[8192]; + if(szText) + { + // Get the name of this item so that we can title the disassembly window + memset(&SelItem, 0, sizeof(SelItem)); + SelItem.mask = TVIF_TEXT; + SelItem.pszText = szText; + SelItem.hItem = pItem->hItem; + SelItem.cchTextMax = 8192; + + WCHAR* wzText = (WCHAR*)szText; + SelItem.cchTextMax /= sizeof(WCHAR); + SendMessageW(g_hwndTreeView, TVM_GETITEMW, 0, (LPARAM) (LPTVITEMW) &SelItem); + unsigned L = ((unsigned)wcslen(wzText)+1)*3; + char* szUTFText = new (nothrow) char[L]; + memset(szUTFText,0,L); + WszWideCharToMultiByte(CP_UTF8,0,wzText,-1,szUTFText,L,NULL,NULL); + delete[] wzText; + szText = szUTFText; + } + HCURSOR hWasCursor = SetCursor(hWaitCursor); + + HWND hRet = GUIDisassemble(pClassItem->cl, pClassItem->cl, szText ? szText : ""); + if(szText) delete[] szText; + + SetCursor(hWasCursor); + + return hRet; + } + } + } + return NULL; +} + + +void SelectClassByName(__in __nullterminated char *pszFQName) +{ + ClassItem_t *pDestItem; + + // Find namespace + char *p = ns::FindSep(pszFQName); + if (p == NULL) + { + pDestItem = FindClassItem(NULL, pszFQName); + } + else + { + char szBuffer[MAX_CLASSNAME_LENGTH]; + strncpy_s(szBuffer, MAX_CLASSNAME_LENGTH,pszFQName, p - pszFQName); + szBuffer[ p - pszFQName ] = '\0'; + pDestItem = FindClassItem(szBuffer, p+1); + } + + if (pDestItem != NULL) + { + SendMessageA(g_hwndTreeView, TVM_SELECTITEM, TVGN_CARET, (LPARAM) (LPTVITEM) pDestItem->hItem); + } +} + +void SelectClassByToken(mdToken tk) +{ + if(TypeFromToken(tk)==mdtTypeDef) + { + ClassItem_t *pDestItem; + if(pDestItem = FindClassItem(tk)) + { + SendMessageA(g_hwndTreeView, TVM_SELECTITEM, TVGN_CARET, (LPARAM) (LPTVITEM) pDestItem->hItem); + } + } +} + +// +// Text search in rich text edit +// +void FindTextInListbox(HWND hwnd, FINDREPLACEW* lpfr) +{ + HWND hwndLB = FindAssociatedDisassemblyListBox(hwnd); + if(hwndLB) + { + FINDTEXTW strFind; + DWORD bgn,end; + SendMessage(hwndLB,EM_GETSEL,(WPARAM)&bgn,(LPARAM)&end); + if(lpfr->Flags & FR_DOWN) + { + strFind.chrg.cpMin=end; + strFind.chrg.cpMax=-1; + } + else + { + strFind.chrg.cpMin=bgn; + strFind.chrg.cpMax=0; + } + strFind.lpstrText=lpfr->lpstrFindWhat; + int pos = (int)SendMessage(hwndLB,EM_FINDTEXTW,(WPARAM)(lpfr->Flags),(LPARAM)&strFind); + if(pos >= 0) + { + //char sz[32]; + //sprintf(sz,"%d:%d",strFind.chrg.cpMin,strFind.chrg.cpMax); + //MessageBox(hwnd,sz,"Find",MB_OK); + SendMessage(hwndLB,EM_SETSEL,(WPARAM)pos,(LPARAM)(pos+wcslen(lpfr->lpstrFindWhat))); + } + } +} + +// +// Disassembly window(s) WndProc +// +LRESULT CALLBACK DisassemblyWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + static HBRUSH hBrush=NULL; + COLORREF crBackGr; + + static COLORREF crBackGrOld=NULL; + + if (crBackGrOld == NULL) + crBackGrOld = GetSysColor(COLOR_INFOBK); + + if(uMsg== g_uFindReplaceMsg) + { + FINDREPLACEW* lpfr = (FINDREPLACEW*)lParam; + if(!(lpfr->Flags & FR_DIALOGTERM)) + { + FindTextInListbox(hwnd,lpfr); + } + } + else + switch (uMsg) + { + case WM_CREATE: + hBrush = CreateSolidBrush(RGB(255,255,255)); + break; + + //===== Sent by Static (label) and Read-Only Edit field ===== + case WM_CTLCOLORSTATIC: + case WM_CTLCOLOREDIT: + if(hBrush) DeleteObject(hBrush); + crBackGr = GetSysColor(COLOR_INFOBK); + hBrush = CreateSolidBrush(crBackGr); + SetBkColor((HDC) wParam, crBackGr); + if(crBackGr != crBackGrOld) + { + g_strChFontDasm.rgbColors = GetSysColor(COLOR_INFOTEXT); + crBackGrOld = crBackGr; + } + SetTextColor((HDC) wParam, g_strChFontDasm.rgbColors); + return (LRESULT) hBrush; + + //====== Sent by active Edit field ============ + //case WM_CTLCOLOREDIT: + // if(hBrush) DeleteObject(hBrush); + // hBrush = CreateSolidBrush(RGB(255,255,255)); + // SetBkColor((HDC) wParam, RGB(255,255,255)); + // return (LRESULT) hBrush; + + // Ownerdraw stuff + case WM_MEASUREITEM: + { + ((MEASUREITEMSTRUCT *) (lParam))->itemHeight = g_Height; + break; + } + + // Ownerdraw stuff + case WM_DRAWITEM: + { + DRAWITEMSTRUCT *pDIS; + WCHAR wzBuf[1024]; + int ItemID; + + pDIS = (DRAWITEMSTRUCT *) lParam; + ItemID = (int) pDIS->itemID; + + if (ItemID < 0) + { + switch (pDIS->CtlType) + { + case ODT_LISTBOX: + { + if ((pDIS->itemAction) & (ODA_FOCUS)) + DrawFocusRect (PHDC, &PRC); + break; + } + + case ODT_COMBOBOX: + { + if ((pDIS->itemAction) & ODS_FOCUS) + DrawFocusRect(PHDC, &PRC); + break; + } + } + + return TRUE; + } + + switch (pDIS->CtlType) + { + case ODT_LISTBOX: + WszSendMessage(pDIS->hwndItem, LB_GETTEXT, pDIS->itemID, (LPARAM)wzBuf); + break; + + case ODT_COMBOBOX: + WszSendMessage(pDIS->hwndItem, CB_GETLBTEXT, pDIS->itemID, (LPARAM)wzBuf); + break; + } + + int crBack,crText; + HBRUSH hbrBack; + + if ((pDIS->itemState) & (ODS_SELECTED)) + { + crBack = GetSysColor(COLOR_HIGHLIGHT); + crText = GetSysColor(COLOR_HIGHLIGHTTEXT); + } + else + { + crBack = GetSysColor(COLOR_WINDOW); + crText = GetSysColor(COLOR_WINDOWTEXT); + } + + hbrBack = CreateSolidBrush(crBack); + FillRect(PHDC, &PRC, hbrBack); + DeleteObject(hbrBack); + + // 0x00bbggrr + SetBkColor(PHDC, crBack); + + // Instruction counter + if (wcslen(wzBuf) >= PADDING && isdigit(*wzBuf)) + { + SetTextColor(PHDC, 0x00FF0000); + TextOutW(PHDC, PRC.left, PRC.top, wzBuf, 5); + + SetTextColor(PHDC, 0x00005500); + TextOutW(PHDC, PRC.left + (5*g_MaxCharWidth), PRC.top, &wzBuf[5], PADDING-5); + + SetTextColor(PHDC, crText); + TextOutW(PHDC, PRC.left + (PADDING*g_MaxCharWidth), PRC.top, &wzBuf[PADDING], (UINT32)wcslen(&wzBuf[PADDING])); + } + else + TextOutW(PHDC, PRC.left, PRC.top, wzBuf, (UINT32)wcslen(wzBuf)); + + if ((pDIS->itemState) & (ODS_FOCUS)) + DrawFocusRect(PHDC, &PRC); + + break; + } + + + case WM_COMMAND: + { + if(HIWORD(wParam) > 1) break; // we are interested in commands from menu only + switch (LOWORD(wParam)) + { + case IDM_FIND: + { + HWND hwndLB = FindAssociatedDisassemblyListBox(hwnd); + if(hwndLB) + { + FINDREPLACEW *pFR = &(FindDisasmBoxByHwnd(hwnd)->strFR); + if(pFR && (pFR->Flags&FR_DIALOGTERM)) // i.e., if the box isn't up + { + DWORD bgn,end; + WszSendMessage(hwndLB,EM_GETSEL,(WPARAM)&bgn,(LPARAM)&end); + if(end > bgn) + { + if(end - bgn > 119) + SendMessage(hwndLB,EM_SETSEL,(WPARAM)bgn,(LPARAM)(bgn+119)); + SendMessage(hwndLB,EM_GETSELTEXT,0,(LPARAM)(pFR->lpstrFindWhat)); + } + pFR->Flags &= ~FR_DIALOGTERM; + g_hFindText = FindTextW(pFR); + } + } + } + break; + case IDM_FINDNEXT: + { + FindTextInListbox(hwnd,&(FindDisasmBoxByHwnd(hwnd)->strFR)); + } + break; + } + break; + } + + case WM_SETFOCUS: + SetFocus(FindAssociatedDisassemblyListBox(hwnd)); + break; + + case WM_SIZE: + { + DWORD cxClient = LOWORD(lParam); + DWORD cyClient = HIWORD(lParam); + HWND hListView; + + // We have to size the listview also + + // Will be NULL if we are ourselves a listview + hListView = FindAssociatedDisassemblyListBox(hwnd); + + if (hListView != NULL) + { + // Resize listview window + MoveWindow( + hListView, + 0, + 0, + cxClient, + cyClient, + TRUE // repaint + ); + } + + break; + } + + case WM_CLOSE: + if(hBrush) DeleteObject(hBrush); + if(LOWORD(wParam)==0) RemoveDisasmBox(hwnd); + DestroyWindow(hwnd); // Generates the WM_DESTROY message + + // Shutdown everything if we're just viewing GUI IL and close all our boxes + if (IsGuiILOnly() && (g_NumDisasmBoxes == 0)) { + PostQuitMessage(0); + } + + break; + + default : + return WszDefWindowProc(hwnd, uMsg, wParam, lParam); + } + + return 0; +} + +BOOL CALLBACK AboutBoxProc(HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + switch(uMsg) + { + case WM_INITDIALOG: + { + WCHAR str[1024]; + WszSendDlgItemMessage(hwndDlg,IDC_ABOUT_LINE1,WM_SETTEXT,0, + (LPARAM)RstrW(IDS_ILDASM_TITLE)); + swprintf_s(str,1024,RstrW(IDS_VERSION), VER_FILEVERSION_STR_L); str[1023]=0; + WszSendDlgItemMessage(hwndDlg,IDC_ABOUT_LINE2,WM_SETTEXT,0,(LPARAM)str); + WszSendDlgItemMessage(hwndDlg,IDC_ABOUT_LINE3,WM_SETTEXT,0, + (LPARAM)RstrW(IDS_LEGALCOPYRIGHT)); + } + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case ID_ABOUT_OK: + EndDialog(hwndDlg,0); + return TRUE; + } + break; + + } + return FALSE; +} + +BOOL CALLBACK DumpOptionsProc(HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + static BOOL fAsmChecked; + static BOOL fMetaChecked; + static ULONG uCodePage = 0; + + if (uCodePage == 0) + uCodePage = g_uCodePage; + + switch(uMsg) + { + case WM_INITDIALOG: + WszSendDlgItemMessage(hwndDlg,IDC_RADIO1,BM_SETCHECK,(uCodePage==g_uConsoleCP ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_RADIO2,BM_SETCHECK,(uCodePage==CP_UTF8 ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_RADIO3,BM_SETCHECK,(uCodePage==0xFFFFFFFF ? BST_CHECKED : BST_UNCHECKED),0); + + + WszSendDlgItemMessage(hwndDlg,IDC_CHECK18,BM_SETCHECK,(g_fShowProgressBar ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK1, BM_SETCHECK,(g_fDumpHeader ? BST_CHECKED : BST_UNCHECKED),0); + if(g_fTDC) + { + WszSendDlgItemMessage(hwndDlg,IDC_CHECK2, BM_SETCHECK,(g_fDumpStats ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK19, BM_SETCHECK,(g_fDumpClassList ? BST_CHECKED : BST_UNCHECKED),0); + } + else + { + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK19), SW_HIDE); + } + WszSendDlgItemMessage(hwndDlg,IDC_CHECK3, BM_SETCHECK,(g_fDumpAsmCode ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK4, BM_SETCHECK,(g_fDumpTokens ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK5, BM_SETCHECK,(g_fShowBytes ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK6, BM_SETCHECK,(g_fShowSource ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK20, BM_SETCHECK,(g_fInsertSourceLines ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK7, BM_SETCHECK,(g_fTryInCode ? BST_CHECKED : BST_UNCHECKED),0); + if(!(fAsmChecked = g_fDumpAsmCode)) + { + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK4), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK5), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK6), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK7), FALSE); + } + if(g_fTDC) + { + WszSendDlgItemMessage(hwndDlg,IDC_CHECK8, BM_SETCHECK,(g_fDumpMetaInfo ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK10,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpHeader ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK11,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpMoreHex ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK12,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpCSV ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK13,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpUnsat ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK16,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpValidate ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK14,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpSchema ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK15,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpRaw ? BST_CHECKED : BST_UNCHECKED),0); + WszSendDlgItemMessage(hwndDlg,IDC_CHECK17,BM_SETCHECK,(g_ulMetaInfoFilter & MDInfo::dumpRawHeaps ? BST_CHECKED : BST_UNCHECKED),0); + if(!(fMetaChecked = g_fDumpMetaInfo)) + { + //EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK9), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK10), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK11), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK12), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK13), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK14), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK15), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK16), FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK17), FALSE); + } + } + else + { + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK8), SW_HIDE); + //ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK9), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK10), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK11), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK12), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK13), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK14), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK15), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK16), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK17), SW_HIDE); + } + ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK9), SW_HIDE); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CHECK3: + fAsmChecked = !fAsmChecked; + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK4), fAsmChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK5), fAsmChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK6), fAsmChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK7), fAsmChecked); + return TRUE; + + case IDC_CHECK8: + fMetaChecked = !fMetaChecked; + //EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK9), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK10), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK11), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK12), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK13), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK14), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK15), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK16), fMetaChecked); + EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK17), fMetaChecked); + return TRUE; + + case IDOK: + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_RADIO1, BM_GETCHECK,0,0)) g_uCodePage = g_uConsoleCP; + else if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_RADIO2, BM_GETCHECK,0,0)) g_uCodePage = CP_UTF8; + else if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_RADIO3, BM_GETCHECK,0,0)) g_uCodePage = 0xFFFFFFFF; + uCodePage = g_uCodePage; + + g_fShowProgressBar = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK18, BM_GETCHECK,0,0)); + g_fDumpHeader = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK1, BM_GETCHECK,0,0)); + if(g_fTDC) + { + g_fDumpStats = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK2, BM_GETCHECK,0,0)); + g_fDumpClassList = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK19, BM_GETCHECK,0,0)); + } + g_fDumpAsmCode = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK3, BM_GETCHECK,0,0)); + g_fDumpTokens = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK4, BM_GETCHECK,0,0)); + g_fShowBytes = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK5, BM_GETCHECK,0,0)); + g_fShowSource = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK6, BM_GETCHECK,0,0)); + g_fInsertSourceLines = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK20, BM_GETCHECK,0,0)); + g_fTryInCode = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK7, BM_GETCHECK,0,0)); + if(g_fTDC) + { + g_fDumpMetaInfo = (BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK8, BM_GETCHECK,0,0)); + g_ulMetaInfoFilter = 0; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK10, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpHeader; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK11, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpMoreHex; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK12, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpCSV; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK13, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpUnsat; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK16, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpValidate; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK14, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpSchema; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK15, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpRaw; + if(BST_CHECKED==WszSendDlgItemMessage(hwndDlg,IDC_CHECK17, BM_GETCHECK,0,0)) g_ulMetaInfoFilter |= MDInfo::dumpRawHeaps; + } + EndDialog(hwndDlg,1); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg,0); + return TRUE; + } + break; + + } + return FALSE; +} + +static HWND help_hw; +void * __cdecl HelpFileLoader(_In_z_ LPCWSTR lpHelpFileName) +{ + return HtmlHelpW(help_hw, lpHelpFileName, HH_DISPLAY_TOPIC, NULL); +} + +// +// Main window WndProc +// +#define CHECK_UNCHECK(x) { x=!x; CheckMenuItem(g_hMenu, LOWORD(wParam), (x ? MF_CHECKED : MF_UNCHECKED)); } + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +LRESULT CALLBACK MainWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + HWND hwndDasm; + static HCURSOR hWaitCursor = NULL; + + if (hWaitCursor == NULL) + hWaitCursor = WszLoadCursor(NULL,IDC_WAIT); + + switch (uMsg) + { + case WM_DROPFILES: + { + WCHAR wzFileName[MAX_FILENAME_LENGTH]; + DragQueryFileW((HDROP)wParam,0,wzFileName,MAX_FILENAME_LENGTH-1); + memset(g_szInputFile,0,MAX_FILENAME_LENGTH); + WszWideCharToMultiByte(CP_UTF8,0,wzFileName,-1,g_szInputFile,MAX_FILENAME_LENGTH-1,NULL,NULL); + GetInputFileFullPath(); + { + HCURSOR hWasCursor = SetCursor(hWaitCursor); + GUICleanupClassItems(); + TreeView_DeleteAllItems(g_hwndTreeView); + Cleanup(); + GUISetModule(g_szInputFile); + DumpFile(); + SetCursor(hWasCursor); + } + DragFinish((HDROP)wParam); + } + break; + + case WM_COMMAND: + { + if(HIWORD(wParam) > 1) break; // we are interested in commands from menu only + switch (LOWORD(wParam)) + { + case IDM_OPEN: + { + WCHAR wzInputFile[MAX_FILENAME_LENGTH]; + memset(wzInputFile,0,sizeof(wzInputFile)); + if(strlen(g_szInputFile)) + { + WszMultiByteToWideChar(CP_UTF8,0,g_szInputFile,-1,wzInputFile,MAX_FILENAME_LENGTH-1); + } + { + OPENFILENAMEW ofn; + WCHAR* wzFilter = RstrW(IDS_FILTER_IN); //L"PE file (*.exe,*.dll,*.mod,*.mdl,*.winmd)\0*.exe;*.dll;*.mod;*.mdl;*.winmd\0Any type (*.*)\0*.*\0\0"; + const WCHAR* wzDefltExt = L"exe"; + for(WCHAR* pwc = wzFilter; pwc = wcschr(pwc,'\t'); pwc++) *pwc = 0; + memset(&ofn,0,sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = wzFilter; + ofn.nFilterIndex = 0; + ofn.lpstrFile = wzInputFile; + ofn.nMaxFile = MAX_FILENAME_LENGTH-1; + ofn.Flags = OFN_FILEMUSTEXIST; + ofn.lpstrDefExt = wzDefltExt; + if(GetOpenFileName(&ofn)) + { + HCURSOR hWasCursor = SetCursor(hWaitCursor); + GUICleanupClassItems(); + TreeView_DeleteAllItems(g_hwndTreeView); + Cleanup(); + memset(g_szInputFile,0,MAX_FILENAME_LENGTH); + WszWideCharToMultiByte(CP_UTF8,0,wzInputFile,-1,g_szInputFile,MAX_FILENAME_LENGTH-1,NULL,NULL); + GetInputFileFullPath(); + GUISetModule(g_szInputFile); + DumpFile(); + SetCursor(hWasCursor); + } + } + break; + } + case IDM_ABOUT: + { + _ASSERTE(g_hResources != NULL); + WszDialogBoxParam(g_hResources,MAKEINTRESOURCE(IDD_ABOUT),hwnd,(DLGPROC)AboutBoxProc,0L); + break; + } + case IDM_DUMP: + //case IDM_DUMP_TREE: + if(g_pImport) + { + unsigned uWasCodePage = g_uCodePage; + WCHAR wzOutputFile[MAX_FILENAME_LENGTH]; + memset(wzOutputFile,0,sizeof(wzOutputFile)); + if(strlen(g_szOutputFile)) + { + WszMultiByteToWideChar(CP_UTF8,0,g_szOutputFile,-1,wzOutputFile,MAX_FILENAME_LENGTH-1); + } + { + OPENFILENAMEW ofn; + WCHAR* wzFilter = RstrW(IDS_FILTER_OUT);//L"IL file (*.il)\0*.il\0Text file (*.txt) \0*.txt\0Any type (*.*)\0*.*\0\0"; + const WCHAR* wzDefltExt = L"il"; + for(WCHAR* pwc = wzFilter; pwc = wcschr(pwc,'\t'); pwc++) *pwc = 0; + memset(&ofn,0,sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = wzFilter; + ofn.nFilterIndex = 0; + ofn.lpstrFile = wzOutputFile; + ofn.nMaxFile = MAX_FILENAME_LENGTH-1; + ofn.Flags = OFN_OVERWRITEPROMPT; + ofn.lpstrDefExt = wzDefltExt; + _ASSERTE(g_hResources != NULL); + if(WszDialogBoxParam(g_hResources,MAKEINTRESOURCE(IDD_DIALOG1),hwnd,(DLGPROC)DumpOptionsProc,0L) && + GetSaveFileName(&ofn)) + { + HCURSOR hWasCursor = SetCursor(hWaitCursor); + g_Mode &= ~MODE_GUI; + memset(g_szOutputFile,0,MAX_FILENAME_LENGTH); + WszWideCharToMultiByte(CP_UTF8,0,wzOutputFile,-1,g_szOutputFile,MAX_FILENAME_LENGTH-1,NULL,NULL); + g_pFile = OpenOutput(wzOutputFile); + if(g_pFile) + { + DumpFile(); // closes g_pFile upon completion + SetCursor(hWasCursor); + } + else + { + SetCursor(hWasCursor); + WszMessageBox(hwnd,wzOutputFile,RstrW(IDS_CANNOTOPENFILE),MB_OK|MB_ICONERROR | GetDasmMBRTLStyle()); + } + g_szOutputFile[0] = 0; + g_Mode |= MODE_GUI; + //g_fShowSource = FALSE; // flag could have been changed for dump + } + } + g_uCodePage = uWasCodePage; // g_uCodePage is changed in DumpOptionsProc + } + break; + + case IDM_DUMP_TREE: + if(g_pImport) + { + // Dump the tree view(fully expanded, with current sorting) to a text file + OPENFILENAMEW ofn; + WCHAR* wzFilter = RstrW(IDS_FILTER_OUT2); //L"Text file (*.txt) \0*.txt\0Any type (*.*)\0*.*\0\0"; + const WCHAR* wzDefltExt = L"txt"; + WCHAR szIndent[MAX_FILENAME_LENGTH]; + FILE* pFile; + WCHAR wzOutputFile[MAX_FILENAME_LENGTH]; + for(WCHAR* pwc = wzFilter; pwc = wcschr(pwc,'\t'); pwc++) *pwc = 0; + memset(wzOutputFile,0,sizeof(wzOutputFile)); + memset(&ofn,0,sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = wzFilter; + ofn.nFilterIndex = 0; + ofn.lpstrFile = wzOutputFile; + ofn.nMaxFile = MAX_FILENAME_LENGTH-1; + ofn.Flags = OFN_OVERWRITEPROMPT; + ofn.lpstrDefExt = wzDefltExt; + if(GetSaveFileName(&ofn)) + { + HCURSOR hWasCursor = SetCursor(hWaitCursor); + pFile = g_pFile; + g_pFile = OpenOutput(wzOutputFile); + szIndent[0] = 0; + if(g_pFile) + { + g_Mode &= ~MODE_GUI; + DumpTreeItem(g_hRoot,g_pFile,szIndent); + g_Mode |= MODE_GUI; + fclose(g_pFile); + SetCursor(hWasCursor); + } + else + { + SetCursor(hWasCursor); + WszMessageBox(hwnd,wzOutputFile,RstrW(IDS_CANNOTOPENFILE),MB_OK|MB_ICONERROR | GetDasmMBRTLStyle()); + } + g_pFile = pFile; + } + } + break; + + case IDM_EXIT: + { + WszSendMessage(GetActiveWindow(),WM_CLOSE,0,0); + } + break; + + case IDM_FONT_TREE: + { + g_strChFontTree.hwndOwner = g_hwndMain; + if(ChooseFont(&g_strChFontTree)) + { + DeleteObject((HGDIOBJ)g_hSmallFont); + g_hSmallFont = CreateFontIndirect(&g_strLogFontTree); + WszSendMessage(g_hwndTreeView,WM_SETFONT,(LPARAM) g_hSmallFont,TRUE); + if(g_hwndAsmInfo) + WszSendMessage(g_hwndAsmInfo,WM_SETFONT,(LPARAM) g_hSmallFont,TRUE); + SaveGUIFonts(&guiInfo); + } + break; + } + + case IDM_FONT_DASM: + { + g_strChFontDasm.hwndOwner = g_hwndMain; + if(ChooseFont(&g_strChFontDasm)) + { + if(g_fDumpRTF) { g_strLogFontDasm.lfWeight = FW_REGULAR; g_strLogFontDasm.lfItalic = FALSE; } + DeleteObject((HGDIOBJ)g_hFixedFont); + g_hFixedFont = CreateFontIndirect(&g_strLogFontDasm); + + for (DWORD i = 0; i < g_NumDisasmBoxes; i++) + { + WszSendMessage((*g_DisasmBox)[i].hwndChild,WM_SETFONT,(LPARAM)g_hFixedFont,TRUE); + if(g_fDumpRTF) + GUIDumpItemToDisassemblyEditBox((void*)(*g_DisasmBox)[i].hwndChild, + (*g_DisasmBox)[i].tkClass,(*g_DisasmBox)[i].tkMember); + } + SaveGUIFonts(&guiInfo); + } + break; + } + + case IDM_CAVERBAL: + { + CHECK_UNCHECK(g_fCAVerbal); + for (DWORD i = 0; i < g_NumDisasmBoxes; i++) + { + GUIDumpItemToDisassemblyEditBox((void*)(*g_DisasmBox)[i].hwndChild, + (*g_DisasmBox)[i].tkClass, + (*g_DisasmBox)[i].tkMember); + } + break; + } + + case IDM_DUMPRTF: + { + CHECK_UNCHECK(g_fDumpRTF); + //GUIDumpAssemblyInfo(); + for (DWORD i = 0; i < g_NumDisasmBoxes; i++) + { + mdToken tkClass = (*g_DisasmBox)[i].tkClass; + mdToken tkMember = (*g_DisasmBox)[i].tkMember; + if((TypeFromToken(tkMember)==0)&&(tkClass==IDM_SHOW_METAINFO)) + continue; + GUIDisassemble(tkClass,tkMember,"UpdateThisDisassemblyBox"); + } + break; + } + + case IDM_SORT_BY_NAME: + { + CHECK_UNCHECK(g_fSortByName); + if(g_pImport) + { + if(!RefreshList()) goto CloseAndDestroy; + } + break; + } + + case IDM_TREEVIEWFCN: + { + CHECK_UNCHECK(g_fTreeViewFCN); + if(g_pImport) + { + if(!RefreshList()) goto CloseAndDestroy; + } + break; + } + + case IDM_SHOW_PUB: + { + CHECK_UNCHECK(g_fHidePub); +UpdateVisibilityOptions: + g_fLimitedVisibility = g_fHidePub || + g_fHidePriv || + g_fHideFam || + g_fHideFAA || + g_fHideFOA || + g_fHidePrivScope || + g_fHideAsm; + if(g_pImport) + { + if(!RefreshList()) DestroyWindow(hwnd); + } + break; + } + case IDM_SHOW_PRIV: + { + CHECK_UNCHECK(g_fHidePriv); + goto UpdateVisibilityOptions; + } + case IDM_SHOW_FAM: + { + CHECK_UNCHECK(g_fHideFam); + goto UpdateVisibilityOptions; + } + case IDM_SHOW_ASM: + { + CHECK_UNCHECK(g_fHideAsm); + goto UpdateVisibilityOptions; + } + case IDM_SHOW_FAA: + { + CHECK_UNCHECK(g_fHideFAA); + goto UpdateVisibilityOptions; + } + case IDM_SHOW_FOA: + { + CHECK_UNCHECK(g_fHideFOA); + goto UpdateVisibilityOptions; + } + case IDM_SHOW_PSCOPE: + { + CHECK_UNCHECK(g_fHidePrivScope); + goto UpdateVisibilityOptions; + } + case IDM_FULL_INFO: + { + CHECK_UNCHECK(g_fFullMemberInfo); + if(g_pImport) + { + if(!RefreshList()) DestroyWindow(hwnd); + } + break; + } + case IDM_BYTES: + { + CHECK_UNCHECK(g_fShowBytes); + break; + } + case IDM_TOKENS: + { + CHECK_UNCHECK(g_fDumpTokens); + break; + } + case IDM_SOURCELINES: + { + CHECK_UNCHECK(g_fShowSource); + break; + } + case IDM_EXPANDTRY: + { + CHECK_UNCHECK(g_fTryInCode); + break; + } + case IDM_QUOTEALLNAMES: + { + CHECK_UNCHECK(g_fQuoteAllNames); + break; + } + case IDM_SHOW_HEADER: + { + GUIDisassemble(IDM_SHOW_HEADER,0,"Headers"); + break; + } + case IDM_SHOW_STAT: + { + GUIDisassemble(IDM_SHOW_STAT,0,"Statistics"); + break; + } + case IDM_HELP: + { + help_hw = hwnd; + FindLocalizedFile(L"ildasm.chm", &HelpFileLoader); + break; + } + case IDM_SHOW_METAINFO: + { + if(g_pImport) + GUIDisassemble(IDM_SHOW_METAINFO,0,"MetaInfo"); + break; + } + case IDM_MI_HEADER: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpHeader) g_ulMetaInfoFilter &= ~MDInfo::dumpHeader; + else g_ulMetaInfoFilter |= MDInfo::dumpHeader; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpHeader ? MF_CHECKED : MF_UNCHECKED)); + if(g_ulMetaInfoFilter & MDInfo::dumpHeader) + { + // HeaderOnly specified, + // Suppress Counts,Sizes, Header,Schema and Header,Schema,Rows + g_ulMetaInfoFilter &= ~MDInfo::dumpCSV; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_CSV, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpSchema; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_SCHEMA, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpRaw; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_RAW, MF_UNCHECKED); + } + return 1; //break; + } + case IDM_MI_HEX: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpMoreHex) g_ulMetaInfoFilter &= ~MDInfo::dumpMoreHex; + else g_ulMetaInfoFilter |= MDInfo::dumpMoreHex; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpMoreHex ? MF_CHECKED : MF_UNCHECKED)); + return 1; //break; + } + case IDM_MI_CSV: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpCSV) g_ulMetaInfoFilter &= ~MDInfo::dumpCSV; + else g_ulMetaInfoFilter |= MDInfo::dumpCSV; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpCSV ? MF_CHECKED : MF_UNCHECKED)); + if(g_ulMetaInfoFilter & MDInfo::dumpCSV) + { + // Counts,Sizes specified, + // Suppress HeaderOnly, Header,Schema and Header,Schema,Rows + g_ulMetaInfoFilter &= ~MDInfo::dumpHeader; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_HEADER, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpSchema; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_SCHEMA, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpRaw; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_RAW, MF_UNCHECKED); + } + return 1; //break; + } + case IDM_MI_UNREX: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpUnsat) g_ulMetaInfoFilter &= ~MDInfo::dumpUnsat; + else g_ulMetaInfoFilter |= MDInfo::dumpUnsat; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpUnsat ? MF_CHECKED : MF_UNCHECKED)); + return 1; //break; + } + case IDM_MI_SCHEMA: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpSchema) g_ulMetaInfoFilter &= ~MDInfo::dumpSchema; + else g_ulMetaInfoFilter |= MDInfo::dumpSchema; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpSchema ? MF_CHECKED : MF_UNCHECKED)); + if(g_ulMetaInfoFilter & MDInfo::dumpSchema) + { + // Header,Schema specified, + // suppress Counts,Sizes, HeaderOnly and Header,Schema,Rows + g_ulMetaInfoFilter &= ~MDInfo::dumpCSV; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_CSV, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpHeader; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_HEADER, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpRaw; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_RAW, MF_UNCHECKED); + } + return 1; //break; + } + case IDM_MI_RAW: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpRaw) g_ulMetaInfoFilter &= ~MDInfo::dumpRaw; + else g_ulMetaInfoFilter |= MDInfo::dumpRaw; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpRaw ? MF_CHECKED : MF_UNCHECKED)); + if(g_ulMetaInfoFilter & MDInfo::dumpRaw) + { + // Header,Schema,Rows specified, + // suppress Counts,Sizes, HeaderOnly and Header,Schema + g_ulMetaInfoFilter &= ~MDInfo::dumpCSV; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_CSV, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpHeader; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_HEADER, MF_UNCHECKED); + g_ulMetaInfoFilter &= ~MDInfo::dumpSchema; + CheckMenuItem(g_hMetaInfoMenu, IDM_MI_SCHEMA, MF_UNCHECKED); + } + return 1; //break; + } + case IDM_MI_HEAPS: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpRawHeaps) g_ulMetaInfoFilter &= ~MDInfo::dumpRawHeaps; + else g_ulMetaInfoFilter |= MDInfo::dumpRawHeaps; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpRawHeaps ? MF_CHECKED : MF_UNCHECKED)); + return 1; //break; + } + case IDM_MI_VALIDATE: + { + WORD iSelection = LOWORD(wParam); + if(g_ulMetaInfoFilter & MDInfo::dumpValidate) g_ulMetaInfoFilter &= ~MDInfo::dumpValidate; + else g_ulMetaInfoFilter |= MDInfo::dumpValidate; + CheckMenuItem(g_hMetaInfoMenu, iSelection, (g_ulMetaInfoFilter & MDInfo::dumpValidate ? MF_CHECKED : MF_UNCHECKED)); + return 1; //break; + } + + } + + break; + } + + case WM_SETFOCUS: + SetFocus(g_hwndTreeView); + break; + + case WM_SIZE: + { + DWORD cxClient = LOWORD(lParam); + DWORD cyClient = HIWORD(lParam); + DWORD dy; + + dy = cyClient >> 3; + if(dy < 50) dy = 50; + if(cyClient < dy+4) cyClient = dy+4; + + // Resize listview window + MoveWindow( + g_hwndTreeView, + 0, + 0, + cxClient, + cyClient-dy-2, + TRUE // repaint + ); + // Resize AsmInfo window + MoveWindow( + g_hwndAsmInfo, + 0, + cyClient-dy-1, + cxClient, + dy, + TRUE // repaint + ); + + break; + } + + case WM_NOTIFY: + { + if (wParam == ID_TREEVIEW) + { + NMHDR * pNMHDR = (NMHDR*) lParam; + switch (pNMHDR->code) + { + case TVN_KEYDOWN: + { + NMTVKEYDOWN *pKeyDown = (NMTVKEYDOWN *) pNMHDR; + + if (pKeyDown->wVKey == '\r') + { + if(DoubleClickSelectedMember(g_CurSelItem) == NULL) + TreeView_Expand(g_hwndTreeView,g_CurSelItem,TVE_TOGGLE); + } + break; + } + + case NM_DBLCLK: + { + hwndDasm = DoubleClickSelectedMember(g_CurSelItem); + if(hwndDasm) + { + PostMessageA(hwndDasm,WM_ACTIVATE,WA_CLICKACTIVE,0); + PostMessageA(hwndDasm,WM_SETFOCUS,0,0); + } + break; + } + + case TVN_SELCHANGEDW: + case TVN_SELCHANGEDA: + { + NMTREEVIEW *pTV = (NMTREEVIEW *) pNMHDR; + /* + TVITEM SelItem; + char szText[256]; + + memset(&SelItem, 0, sizeof(SelItem)); + SelItem.mask = TVIF_TEXT; + SelItem.pszText = szText; + SelItem.cchTextMax = sizeof(szText)-1; + SelItem.hItem = pTV->itemNew.hItem; + + g_CurSelItem = SelItem.hItem; + SendMessageA(g_hwndTreeView, TVM_GETITEM, 0, (LPARAM)&SelItem); + */ + g_CurSelItem = pTV->itemNew.hItem; + break; + } + } + } + + break; + } + + case WM_CLOSE: + CloseAndDestroy: + // HTML help window is closed automatically + { + RECT r; + ShowWindow(hwnd,SW_RESTORE); + GetWindowRect(hwnd,(LPRECT)&r); + guiInfo.x = r.left; + guiInfo.y = r.top; + guiInfo.w = r.right - r.left; + guiInfo.h = r.bottom - r.top; + SaveGUIFonts(&guiInfo); + } + DestroyWindow(hwnd); // Generates the WM_DESTROY message + break; + + case WM_DESTROY : + PostQuitMessage(0); // Puts a WM_QUIT in the queue + break; + + default : + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + + return 0; +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + + +// +// Create the treeview in the main window +// +HWND CreateTreeView(HWND hwndParent) +{ + HWND hwndTree; + RECT rcl; + DWORD tvs = + TVS_HASLINES + |TVS_HASBUTTONS + |TVS_LINESATROOT + |TVS_SHOWSELALWAYS + // |TVS_TRACKSELECT + // |TVS_SINGLEEXPAND + |TVS_DISABLEDRAGDROP + ; + unsigned cy,dy; + + GetClientRect(hwndParent, &rcl); + cy = rcl.bottom - rcl.top; + dy = cy >> 3; + hwndTree = WszCreateWindowEx( + 0, + WC_TREEVIEWW, + NULL, + WS_VISIBLE|WS_CHILD|WS_BORDER|tvs, + 0, + 0, + rcl.right - rcl.left, + cy-dy-2, //rcl.bottom - rcl.top, + hwndParent, + (HMENU) ID_TREEVIEW, + g_hInstance, + NULL + ); + g_hwndAsmInfo = NULL; + if (hwndTree == NULL) + return NULL; + + WszSendMessage(hwndTree,WM_SETFONT,(LPARAM) g_hSmallFont,FALSE); + + TreeView_SetBkColor(hwndTree,-1); + TreeView_SetImageList(hwndTree, g_hImageList, TVSIL_NORMAL); + + g_hwndAsmInfo = WszCreateWindowEx( + 0, //WS_EX_TOOLWINDOW, + g_fDumpRTF ? L"RichEdit20A" : L"EDIT", + NULL, + WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE | WS_BORDER //| WS_CAPTION | WS_OVERLAPPEDWINDOW + | ES_MULTILINE | ES_READONLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_NOHIDESEL, + 0, + cy-dy-1, + rcl.right - rcl.left, + dy, + hwndParent, + (HMENU) ID_LISTBOX, + g_hInstance, // hinst + NULL + ); + if(g_hwndAsmInfo) + { + WszSendMessage(g_hwndAsmInfo,WM_SETFONT,(LPARAM) g_hSmallFont,FALSE); + } + + return hwndTree; +} + + +// +// Add one item to a treeview +// +HTREEITEM AddOneItem(HTREEITEM hParent, const char *pszText, HTREEITEM hInsAfter, int iImage, HWND hwndTree, BOOL fExpanded) +{ + HTREEITEM hItem; + WCHAR* wz = UtfToUnicode(pszText); + ULONG lLen = (ULONG)wcslen(wz); + TVINSERTSTRUCTW tvIns; + memset(&tvIns, 0, sizeof(tvIns)); + + tvIns.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM; + tvIns.item.pszText = wz; + tvIns.item.cchTextMax = lLen; + tvIns.item.iImage = iImage; + tvIns.item.iSelectedImage = iImage; + + tvIns.hInsertAfter = hInsAfter; + tvIns.hParent = hParent; + + hItem = (HTREEITEM)WszSendMessage(hwndTree, TVM_INSERTITEMW, 0, (LPARAM)(&tvIns)); + + return hItem; +} + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:22018) // Suppress PREFast warning about Integer overflow/underflow +#endif +//ulen cannot be greater than GlobalBufferLen by the definition of ulen. Therefore it's safe to disable this warning here. +void AddMethodToGUI( + mdTypeDef cl, + ClassItem_t * pClassItem, + const char *pszNamespace, + const char *pszClassName, + const char *pszMethodName, + PCCOR_SIGNATURE pComSig, + unsigned cComSig, + mdMethodDef mbMethod, + DWORD dwAttrs +) +{ + HTREEITEM hParent; + char* szName; + ULONG ulLen,ulImageIndex; + BOOL wasDumpRTF; + + memset(GlobalBuffer,0,GlobalBufferLen); + sprintf_s(GlobalBuffer, GlobalBufferLen,g_fFullMemberInfo ? "method %s : ": "%s : ",pszMethodName); + InGlobalBuffer = (UINT32)strlen(GlobalBuffer); + ulLen = InGlobalBuffer; + wasDumpRTF = g_fDumpRTF; + g_fDumpRTF = FALSE; + mdToken tkVarOwner = g_tkVarOwner; + g_tkVarOwner = cl; + DumpMethod(mbMethod, pszClassName,VAL32(g_CORHeader->EntryPointToken),(void *)g_hwndTreeView,FALSE); + g_tkVarOwner = tkVarOwner; + g_fDumpRTF = wasDumpRTF; + GlobalBuffer[InGlobalBuffer-2] = 0; // get rid of \r\n + + szName = &GlobalBuffer[ulLen]; + + if(strstr(szName,"instance ") == szName) strcpy_s(szName,GlobalBufferLen-ulLen,szName+9); + + szName = GlobalBuffer; + + hParent = pClassItem->hItem; + + _ASSERTE(pClassItem->CurMember < pClassItem->SubItems); + + if((strchr(szName, '<'))&&(strchr(szName, '>'))) + { + ulImageIndex = IsMdStatic(dwAttrs) ? STATIC_METHOD_GEN_IMAGE_INDEX : METHOD_GEN_IMAGE_INDEX; + } + else + { + ulImageIndex = IsMdStatic(dwAttrs) ? STATIC_METHOD_IMAGE_INDEX : METHOD_IMAGE_INDEX; + } + + pClassItem->pMembers[pClassItem->CurMember].hItem = AddOneItem( + hParent, szName, TVI_LAST, ulImageIndex, g_hwndTreeView, FALSE + ); + pClassItem->pMembers[pClassItem->CurMember].Discriminator = TREEITEM_TYPE_MEMBER; + pClassItem->pMembers[pClassItem->CurMember].mbMember = mbMethod; + pClassItem->CurMember++; +} + +#ifdef _PREFAST_ +#pragma warning(pop) +#endif +BOOL NamespaceMatch(const char *pszNamespace, __in __nullterminated char *pszString) +{ + if (strncmp(pszNamespace, pszString, strlen(pszNamespace)) == 0) + { + if (pszString[ strlen(pszNamespace) ] == NAMESPACE_SEPARATOR_CHAR) + return TRUE; + } + + return FALSE; +} + +void AddFieldToGUI( + mdTypeDef cl, + ClassItem_t *pClassItem, + const char *pszNamespace, + const char *pszClassName, + const char *pszFieldName, + const char *pszSignature, + mdFieldDef mbField, + DWORD dwAttrs +) +{ + DWORD Dimensions; + ULONG ul1,ul2; + BOOL wasDumpRTF; + HTREEITEM hParent = pClassItem->hItem; + + Dimensions = 0; + + memset(GlobalBuffer,0,GlobalBufferLen); + sprintf_s(GlobalBuffer,GlobalBufferLen,g_fFullMemberInfo ? "field %s : " : "%s : ",pszFieldName); + InGlobalBuffer = (UINT32)strlen(GlobalBuffer); + GetClassLayout(cl,&ul1,&ul2); + wasDumpRTF = g_fDumpRTF; + g_fDumpRTF = FALSE; + DumpField(mbField, pszClassName,(void *)g_hwndTreeView,FALSE); + g_fDumpRTF = wasDumpRTF; + GlobalBuffer[InGlobalBuffer-2] = 0; // get rid of \r\n + char* pch = strchr(GlobalBuffer,'\r'); + if(pch) strcpy_s(pch,5," ..."); + _ASSERTE(pClassItem->CurMember < pClassItem->SubItems); + + pClassItem->pMembers[pClassItem->CurMember].mbMember = mbField; + pClassItem->pMembers[pClassItem->CurMember].Discriminator = TREEITEM_TYPE_MEMBER; + pClassItem->pMembers[pClassItem->CurMember++].hItem = AddOneItem( + hParent, + GlobalBuffer, //szType, + TVI_LAST, + (dwAttrs & mdStatic) ? STATIC_FIELD_IMAGE_INDEX : FIELD_IMAGE_INDEX, + g_hwndTreeView, + FALSE + ); +} + +void AddEventToGUI( + mdTypeDef cl, + ClassItem_t *pClassItem, + const char *pszNamespace, + const char *pszClassName, + DWORD dwClassAttrs, + mdEvent mbEvent +) +{ + DWORD Dimensions; + BOOL wasDumpRTF; + HTREEITEM hParent = pClassItem->hItem; + + Dimensions = 0; + + memset(GlobalBuffer,0,GlobalBufferLen); + if(g_fFullMemberInfo) strcpy_s(GlobalBuffer,GlobalBufferLen,"event "); + InGlobalBuffer = (UINT32)strlen(GlobalBuffer); + wasDumpRTF = g_fDumpRTF; + g_fDumpRTF = FALSE; + DumpEvent(mbEvent, pszClassName, dwClassAttrs, (void *)g_hwndTreeView, FALSE); //FALSE=don't dump the body + g_fDumpRTF = wasDumpRTF; + GlobalBuffer[InGlobalBuffer-2] = 0; // get rid of \r\n + + _ASSERTE(pClassItem->CurMember < pClassItem->SubItems); + + pClassItem->pMembers[pClassItem->CurMember].mbMember = mbEvent; + pClassItem->pMembers[pClassItem->CurMember].Discriminator = TREEITEM_TYPE_MEMBER; + pClassItem->pMembers[pClassItem->CurMember++].hItem = AddOneItem( + hParent, + GlobalBuffer, //szType, + TVI_LAST, + EVENT_IMAGE_INDEX, + g_hwndTreeView, + FALSE + ); +} + +void AddPropToGUI( + mdTypeDef cl, + ClassItem_t *pClassItem, + const char *pszNamespace, + const char *pszClassName, + DWORD dwClassAttrs, + mdProperty mbProp +) +{ + DWORD Dimensions; + BOOL wasDumpRTF; + HTREEITEM hParent = pClassItem->hItem; + + Dimensions = 0; + + memset(GlobalBuffer,0,GlobalBufferLen); + if(g_fFullMemberInfo) strcpy_s(GlobalBuffer,GlobalBufferLen,"prop "); + InGlobalBuffer = (UINT32)strlen(GlobalBuffer); + wasDumpRTF = g_fDumpRTF; + g_fDumpRTF = FALSE; + DumpProp(mbProp, pszClassName, dwClassAttrs, (void *)g_hwndTreeView, FALSE); //FALSE=don't dump the body + g_fDumpRTF = wasDumpRTF; + GlobalBuffer[InGlobalBuffer-2] = 0; // get rid of \r\n + + _ASSERTE(pClassItem->CurMember < pClassItem->SubItems); + + pClassItem->pMembers[pClassItem->CurMember].mbMember = mbProp; + pClassItem->pMembers[pClassItem->CurMember].Discriminator = TREEITEM_TYPE_MEMBER; + pClassItem->pMembers[pClassItem->CurMember++].hItem = AddOneItem( + hParent, + GlobalBuffer, //szType, + TVI_LAST, + PROP_IMAGE_INDEX, + g_hwndTreeView, + FALSE + ); +} + + + +HTREEITEM FindCreateNamespaceRoot(const char *pszNamespace) +{ + DWORD i; + HTREEITEM hRoot; + DWORD l = 0,ll; + + if (!pszNamespace || !*pszNamespace) + return g_hRoot; // not in a namespace, use tree root + + hRoot = g_hRoot; + for (i = 0; i < g_NumNamespaces; i++) + { + if (!strcmp(pszNamespace, (*g_NamespaceList)[i].pszNamespace)) + return (*g_NamespaceList)[i].hRoot; + } + for (i = 0; i < g_NumNamespaces; i++) + { + if(strstr(pszNamespace,(*g_NamespaceList)[i].pszNamespace) == pszNamespace) + { + ll = (DWORD)strlen((*g_NamespaceList)[i].pszNamespace); + if((ll > l)&&(pszNamespace[ll] == '.')) + { + hRoot = (*g_NamespaceList)[i].hRoot; + l = ll; + } + } + } + + hRoot = AddOneItem(hRoot, pszNamespace, TVI_LAST, NAMESPACE_IMAGE_INDEX, g_hwndTreeView, TRUE); + (*g_NamespaceList)[g_NumNamespaces].pszNamespace = pszNamespace; + (*g_NamespaceList)[g_NumNamespaces].hRoot = hRoot; + g_NumNamespaces++; + + return hRoot; +} + + +Namespace_t *FindNamespace(const char *pszNamespace) +{ + DWORD i; + + for (i = 0; i < g_NumNamespaces; i++) + { + if (!strcmp(pszNamespace, (*g_NamespaceList)[i].pszNamespace)) + return &(*g_NamespaceList)[i]; + } + + return NULL; +} + + +void GUICleanupClassItems() +{ + DWORD i; + WCHAR* sz=L"\0\0"; + + for (i = 0; i < g_NumClassItems; i++) + { + if((*g_ClassItemList)[i].pMembers) + { + delete[] (*g_ClassItemList)[i].pMembers; + (*g_ClassItemList)[i].pMembers = NULL; + } + } + for (i = 0; i < g_NumDisasmBoxes; i++) + { + PostMessageA((*g_DisasmBox)[i].hwndContainer,WM_CLOSE,0,0); + } + WszSendMessage(g_hwndAsmInfo,WM_SETTEXT,0,(LPARAM)sz); + EnableMenuItem(g_hMenu,(UINT)(UINT_PTR)g_hViewMenu, MF_GRAYED); + EnableMenuItem(g_hFileMenu,IDM_DUMP,MF_GRAYED); + EnableMenuItem(g_hFileMenu,IDM_DUMP_TREE,MF_GRAYED); +} + +// +// Add a new class tree node +// +ClassItem_t *AddClassToGUI( + mdTypeDef cl, + UINT uImageIndex, + const char *pszNamespace, + const char *pszClassName, + DWORD cSubItems, + HTREEITEM *phRoot // Returns the namespace root (NOT the class root) +) +{ + HTREEITEM hRoot; + + if(*phRoot) + hRoot = *phRoot; + else + { + hRoot = FindCreateNamespaceRoot(pszNamespace); + _ASSERTE(hRoot != NULL); + + *phRoot = hRoot; + } + + (*g_ClassItemList)[g_NumClassItems].hItem = AddOneItem(hRoot, pszClassName, TVI_LAST, uImageIndex, g_hwndTreeView, FALSE); + (*g_ClassItemList)[g_NumClassItems].cl = cl; + (*g_ClassItemList)[g_NumClassItems].SubItems = cSubItems; + (*g_ClassItemList)[g_NumClassItems].CurMember = 0; + + (*g_ClassItemList)[g_NumClassItems].pMembers = new (nothrow) TreeItem_t[cSubItems]; + + g_NumClassItems++; + + return &(*g_ClassItemList)[g_NumClassItems-1]; +} + + +void AddGlobalFunctions() +{ + HRESULT hr = S_OK; + HENUMInternal hEnumMethod; + mdToken FuncToken; + DWORD i; + HTREEITEM hNamespaceRoot = NULL; + DWORD NumGlobals; + + ClassItem_t* pClassItem = &(*g_ClassItemList)[0]; + + if (SUCCEEDED(g_pImport->EnumGlobalFieldsInit(&hEnumMethod))) + { + NumGlobals = g_pImport->EnumGetCount(&hEnumMethod); + MemberInfo* fields = new (nothrow) MemberInfo[NumGlobals]; + MemberInfo* curField = fields; + + for (i = 0; g_pImport->EnumNext(&hEnumMethod, &FuncToken); i++) + { + curField->token = FuncToken; + if (FAILED(g_pImport->GetFieldDefProps(FuncToken, &curField->dwAttrs)) || + FAILED(g_pImport->GetNameOfFieldDef(FuncToken, &curField->pszMemberName))) + { + curField->pszMemberName = "Invalid FieldDef record"; + } + MAKE_NAME_IF_NONE(curField->pszMemberName,FuncToken); + //curField->pComSig = g_pImport->GetSigOfFieldDef(FuncToken, &curMethod->cComSig); + curField++; + } + g_pImport->EnumClose(&hEnumMethod); + + _ASSERTE(curField - fields == (int) NumGlobals); + + if(g_fSortByName) qsort(fields, NumGlobals, sizeof MemberInfo, memberCmp); + + for(curField = fields; curField < &fields[NumGlobals];curField++) + { + if(g_fLimitedVisibility) + { + if(g_fHidePub && IsFdPublic(curField->dwAttrs)) continue; + if(g_fHidePriv && IsFdPrivate(curField->dwAttrs)) continue; + if(g_fHideFam && IsFdFamily(curField->dwAttrs)) continue; + if(g_fHideAsm && IsFdAssembly(curField->dwAttrs)) continue; + if(g_fHideFOA && IsFdFamORAssem(curField->dwAttrs)) continue; + if(g_fHideFAA && IsFdFamANDAssem(curField->dwAttrs)) continue; + if(g_fHidePrivScope && IsFdPrivateScope(curField->dwAttrs)) continue; + } + AddFieldToGUI(NULL, pClassItem, NULL, "Global Fields", curField->pszMemberName, NULL, curField->token, curField->dwAttrs); + } + delete[] fields; + } + if (FAILED(g_pImport->EnumGlobalFunctionsInit(&hEnumMethod))) + return; + + NumGlobals = g_pImport->EnumGetCount(&hEnumMethod); + MemberInfo* methods = new (nothrow) MemberInfo[NumGlobals]; + MemberInfo* curMethod = methods; + + for (i = 0; g_pImport->EnumNext(&hEnumMethod, &FuncToken); i++) + { + curMethod->token = FuncToken; + if (FAILED(g_pImport->GetMethodDefProps(FuncToken, &curMethod->dwAttrs)) || + FAILED(g_pImport->GetNameOfMethodDef(FuncToken, &curMethod->pszMemberName))) + { + curMethod->pszMemberName = "Invalid MethodDef record"; + } + MAKE_NAME_IF_NONE(curMethod->pszMemberName,FuncToken); + if (FAILED(g_pImport->GetSigOfMethodDef(FuncToken, &curMethod->cComSig, &curMethod->pComSig))) + { + curMethod->pszMemberName = "Invalid MethodDef record"; + curMethod->cComSig = 0; + curMethod->pComSig = NULL; + } + curMethod++; + } + g_pImport->EnumClose(&hEnumMethod); + + _ASSERTE(curMethod - methods == (int) NumGlobals); + + if(g_fSortByName) qsort(methods, NumGlobals, sizeof MemberInfo, memberCmp); + + for(curMethod = methods; curMethod < &methods[NumGlobals];curMethod++) + { + if(g_fLimitedVisibility) + { + if(g_fHidePub && IsMdPublic(curMethod->dwAttrs)) continue; + if(g_fHidePriv && IsMdPrivate(curMethod->dwAttrs)) continue; + if(g_fHideFam && IsMdFamily(curMethod->dwAttrs)) continue; + if(g_fHideAsm && IsMdAssem(curMethod->dwAttrs)) continue; + if(g_fHideFOA && IsMdFamORAssem(curMethod->dwAttrs)) continue; + if(g_fHideFAA && IsMdFamANDAssem(curMethod->dwAttrs)) continue; + if(g_fHidePrivScope && IsMdPrivateScope(curMethod->dwAttrs)) continue; + } + AddMethodToGUI(NULL, pClassItem, NULL, "Global Functions", curMethod->pszMemberName, curMethod->pComSig, curMethod->cComSig, curMethod->token, curMethod->dwAttrs); + } + delete[] methods; + return; +} + + +BOOL CreateMainWindow() +{ + DWORD dwStyle, dwStyleEx; + +// If only showing GUI's IL window, than we don't want to see the main window +// However, main window still manages our data, so we have to still create it. :( +// But we can "pretend" it's not there by hiding it (no WS_VISIBLE, and add WS_EX_TOOLWINDOW) + if (IsGuiILOnly()) { + dwStyle = WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_POPUP | WS_SIZEBOX; + dwStyleEx = WS_EX_TOOLWINDOW; + } else { + dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CAPTION | WS_POPUP | WS_SIZEBOX; + dwStyleEx = WS_EX_CLIENTEDGE; + } + g_hwndMain = WszCreateWindowEx(dwStyleEx, + MAIN_WINDOW_CLASSW, + L"IL DASM ", //MAIN_WINDOW_CAPTIONW, + dwStyle, + guiInfo.x, + guiInfo.y, + guiInfo.w, + guiInfo.h, + NULL, + g_hMenu, // menu + g_hInstance, // hinst + NULL + ); + if (g_hwndMain == NULL) + return FALSE; + DragAcceptFiles(g_hwndMain,TRUE); + SendMessageA(g_hwndMain,WM_SETTEXT, 0, (LPARAM)"IL DASM "); + return TRUE; +} + + +// +// Given a CL token, find the classitem for it +// +ClassItem_t *FindClassItem(mdTypeDef cl) +{ + DWORD i; + + for (i = 0; i < g_NumClassItems; i++) + { + if ((*g_ClassItemList)[i].cl == cl) + return &(*g_ClassItemList)[i]; + } + + return NULL; +} + + +// +// Given a class name, find the classitem for it (may fail) +// +ClassItem_t *FindClassItem(__in_opt __nullterminated char *pszFindNamespace, __in __nullterminated char *pszFindName) +{ + DWORD i; + + for (i = 0; i < g_NumClassItems; i++) + { + const char *pszClassName; + const char *pszNamespace; + + if((*g_ClassItemList)[i].cl) + { + + if (FAILED(g_pImport->GetNameOfTypeDef( + (*g_ClassItemList)[i].cl, + &pszClassName, + &pszNamespace))) + { + pszClassName = pszNamespace = "Invalid TypeDef record"; + } + MAKE_NAME_IF_NONE(pszClassName,(*g_ClassItemList)[i].cl); + + if (!strcmp(pszFindName, pszClassName)) + { + if ((((pszFindNamespace == NULL)||(*pszFindNamespace == 0)) + &&((pszNamespace == NULL)||(*pszNamespace == 0))) + ||(!strcmp(pszFindNamespace, pszNamespace))) + return &(*g_ClassItemList)[i]; + } + } + } + //MessageBox(NULL,pszFindName,"Class Not Found",MB_OK); + return NULL; +} + + +ClassItem_t *FindClassItem(HTREEITEM hItem) +{ + DWORD i; + + for (i = 0; i < g_NumClassItems; i++) + { + if ((*g_ClassItemList)[i].hItem == hItem) + return &(*g_ClassItemList)[i]; + } + + return NULL; +} + + +// +// Init GUI components +// +BOOL CreateGUI() +{ + + if (InitGUI() == FALSE) + return FALSE; + + // Register the window class for the main window. + if (CreateMainWindow() == FALSE) + return FALSE; + + g_hwndTreeView = CreateTreeView(g_hwndMain); + if (g_hwndTreeView == NULL) + return FALSE; + + return 0; +} + + +// +// This is the main loop which the disassembler sits in when in GUI mode +// +void GUIMainLoop() +{ + MSG msg; + HACCEL hAccel = NULL; + + _ASSERTE(g_hResources != NULL); + hAccel = WszLoadAccelerators(g_hResources,L"FileAccel"); + // Accelerator tables are released when the app exits + while (WszGetMessage(&msg, (HWND) NULL, 0, 0)) + { + // Dispatch message to appropriate window + if((g_hFindText == NULL)|| !WszIsDialogMessage(g_hFindText,&msg)) + { + if(hAccel && WszTranslateAccelerator(g_hwndMain,hAccel,&msg)); + else + { + TranslateMessage(&msg); + WszDispatchMessage(&msg); + } + } + } + GUICleanupClassItems(); +} +// Dump one tree item to a text file (calls itself recursively) +void DumpTreeItem(HTREEITEM hSelf, FILE* pFile, __inout __nullterminated WCHAR* szIndent) +{ + HTREEITEM hNext; + TVITEMEXW tvi; + static WCHAR szText[2048]; + WCHAR* wzString = (WCHAR*)GlobalBuffer; + tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_TEXT; + tvi.hItem = hSelf; + tvi.pszText = szText; + tvi.cchTextMax = 2047; + if(WszSendMessage(g_hwndTreeView,TVM_GETITEMW,0,(LPARAM)(&tvi))) + { + WCHAR* szType = NULL; + if(hSelf == g_hRoot) szType = L"MOD"; + else + { + switch(tvi.iImage) + { + case CLASS_IMAGE_INDEX: szType = L"CLS"; break; + case EVENT_IMAGE_INDEX: szType = L"EVT"; break; + case FIELD_IMAGE_INDEX: szType = L"FLD"; break; + case NAMESPACE_IMAGE_INDEX: szType = L"NSP"; break; + case METHOD_IMAGE_INDEX: szType = L"MET"; break; + case PROP_IMAGE_INDEX: szType = L"PTY"; break; + case STATIC_FIELD_IMAGE_INDEX: szType = L"STF"; break; + case STATIC_METHOD_IMAGE_INDEX: szType = L"STM"; break; + case CLASSENUM_IMAGE_INDEX: szType = L"ENU"; break; + case CLASSINT_IMAGE_INDEX: szType = L"INT"; break; + case CLASSVAL_IMAGE_INDEX: szType = L"VCL"; break; + } + } + if(szType) swprintf_s(wzString,4096,L"%s___[%s] %s",szIndent,szType,szText); + else swprintf_s(wzString,4096,L"%s %s",szIndent,szText); + } + else swprintf_s(wzString,4096,L"%sGetItemW failed",szIndent); + printLineW(pFile,wzString); + *wzString = 0; + if(hNext = TreeView_GetChild(g_hwndTreeView,hSelf)) + { + wcscat_s(szIndent,MAX_FILENAME_LENGTH,L" |"); + + do { + DumpTreeItem(hNext,pFile,szIndent); + } while(hNext = TreeView_GetNextSibling(g_hwndTreeView,hNext)); + + szIndent[wcslen(szIndent)-4] = 0; + printLineW(pFile,szIndent); + } +} + diff --git a/src/ildasm/gui.h b/src/ildasm/gui.h new file mode 100644 index 0000000000..07233b5aee --- /dev/null +++ b/src/ildasm/gui.h @@ -0,0 +1,156 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "dynamicarray.h" + +#define BITMAP_WIDTH 15 +#define BITMAP_HEIGHT 15 + +#define DISASSEMBLY_CLASS_NAME "disassembly" +#define MAIN_WINDOW_CLASS "dasm" +#define MAIN_WINDOW_CAPTION "IL DASM" + +#define DISASSEMBLY_CLASS_NAMEW L"disassembly" +#define MAIN_WINDOW_CLASSW L"dasm" +#define MAIN_WINDOW_CAPTIONW L"IL DASM\0" + +#define PHDC (pDIS->hDC) +#define PRC (pDIS->rcItem) + +#define PADDING 28 + +#define ID_TREEVIEW 1 +#define ID_LISTBOX 2 + +typedef struct +{ + const char *pszNamespace; + HTREEITEM hRoot; +} Namespace_t; + + +// +// Menu info +// +enum +{ + IDM_PROGRESS, + IDM_OPEN, + IDM_DUMP, + IDM_DUMP_TREE, + IDM_EXIT, + IDM_SORT_BY_NAME, + IDM_SHOW_PUB, + IDM_SHOW_PRIV, + IDM_SHOW_FAM, + IDM_SHOW_ASM, + IDM_SHOW_FAA, + IDM_SHOW_FOA, + IDM_SHOW_PSCOPE, + IDM_FULL_INFO, + IDM_BYTES, + IDM_TOKENS, + IDM_SOURCELINES, + IDM_EXPANDTRY, + IDM_QUOTEALLNAMES, + IDM_SHOW_HEADER, + IDM_SHOW_STAT, + IDM_SHOW_METAINFO, + IDM_MI_DEBUG, + IDM_MI_HEADER, + IDM_MI_HEX, + IDM_MI_CSV, + IDM_MI_UNREX, + IDM_MI_SCHEMA, + IDM_MI_RAW, + IDM_MI_HEAPS, + IDM_MI_VALIDATE, + IDM_HELP, + IDM_ABOUT, + IDM_FONT_TREE, + IDM_FONT_DASM, + IDM_FIND, + IDM_FINDNEXT, + IDM_TREEVIEWFCN, + IDM_CAVERBAL, + IDM_DUMPRTF +}; + + +// +// Bitmaps - keep in same order as in dasm.rc file +// +enum +{ + CLASS_IMAGE_INDEX, + EVENT_IMAGE_INDEX, + METHOD_IMAGE_INDEX, + NAMESPACE_IMAGE_INDEX, + FIELD_IMAGE_INDEX, + PROP_IMAGE_INDEX, + STATIC_METHOD_IMAGE_INDEX, + STATIC_FIELD_IMAGE_INDEX, + RED_ARROW_IMAGE_INDEX, + CLASSENUM_IMAGE_INDEX, + CLASSINT_IMAGE_INDEX, + CLASSVAL_IMAGE_INDEX, + CLASS_GEN_IMAGE_INDEX, + METHOD_GEN_IMAGE_INDEX, + STATIC_METHOD_GEN_IMAGE_INDEX, + CLASSENUM_GEN_IMAGE_INDEX, + CLASSINT_GEN_IMAGE_INDEX, + CLASSVAL_GEN_IMAGE_INDEX, + LAST_IMAGE_INDEX +}; + +#define TREEITEM_TYPE_MEMBER 1 +#define TREEITEM_TYPE_INFO 2 + +// Member items and info items (under classes) +typedef struct +{ + HTREEITEM hItem; + union + { + mdToken mbMember; + char * pszText; // if an info item (extends or implements some class) + }; + BYTE Discriminator; +} TreeItem_t; + +// Class items (under the root) +typedef struct +{ + HTREEITEM hItem; + mdTypeDef cl; + TreeItem_t *pMembers; // List of subitems + DWORD SubItems; // Number of subitems + DWORD CurMember; // Used when building member list +} ClassItem_t; + +typedef struct +{ + HWND hwndContainer; + HWND hwndChild; + HMENU hMenu; + mdToken tkClass; + mdToken tkMember; + WCHAR wzFind[120]; + FINDREPLACEW strFR; +} DisasmBox_t; + + + +// For accessing metadata +extern IMDInternalImport* g_pImport; +extern PELoader * g_pPELoader; +extern IMetaDataImport2* g_pPubImport; + +//extern DynamicArray<mdToken> g_cl_list; +extern mdToken * g_cl_list; +//extern DynamicArray<mdToken> g_cl_enclosing; +extern mdToken * g_cl_enclosing; +extern mdTypeDef g_cl_module; +extern DWORD g_NumClasses; diff --git a/src/ildasm/html/clicking.htm b/src/ildasm/html/clicking.htm new file mode 100644 index 0000000000..828193c988 --- /dev/null +++ b/src/ildasm/html/clicking.htm @@ -0,0 +1,35 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<HTML> +<HEAD> +<META HTTP-EQUIV="Content-Type" Content="text/html; charset=Windows-1252"> +<TITLE>Clicking on Tree View Items</TITLE> + +<STYLE> + BODY {background: white; color: black} + h3 {font: 8pt Arial bold} + P {font: 10pt Arial} + TD {font: 10pt Arial} + A {text-decoration: none; color: blue} +</STYLE> + +</HEAD> + +<BODY BGCOLOR="#FFFFFF" TEXT="#000000"> + +<P style="margin-top: 0; margin-bottom: 0"><A NAME="clicking"><font size="4"> +</font></A><B><I><font size="4">CLICKING ON TREE VIEW ITEMS</font></I></B></P> +<P style="margin-top: 0; margin-bottom: 0"> </P> + +<font size="2"> +<P style="margin-top: 0; margin-bottom: 0">Double-clicking on various tree view items results in the following actions: +<UL> + <LI><P style="margin-top: 0; margin-bottom: 0">On namespace or any type of class - expanding/collapsing respective subtree</LI> + <LI><p style="margin-top: 0; margin-bottom: 0">On manifest, field, method, event, property - showing disassembly of the item in a separate window</LI> + <LI><p style="margin-top: 0; margin-bottom: 0">On <B>.class</B> info item - showing partial disassembly of the class in a separate window</LI> + <LI><p style="margin-top: 0; margin-bottom: 0">On <B>extends</B> info item - selecting the parent class (if present) in tree view</LI> + <LI><p style="margin-top: 0; margin-bottom: 0">On <B>implements</B> info item - selecting the implemented interface (if present) in tree view</LI> +</UL> +</font> + +</BODY> +</HTML> diff --git a/src/ildasm/html/keyboard.htm b/src/ildasm/html/keyboard.htm new file mode 100644 index 0000000000..6730adcc22 --- /dev/null +++ b/src/ildasm/html/keyboard.htm @@ -0,0 +1,166 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<HTML> +<HEAD> +<META HTTP-EQUIV="Content-Type" Content="text/html; charset=Windows-1252"> +<TITLE>Keyboard Commands</TITLE> + +<STYLE> + BODY {background: white; color: black} + h3 {font: 8pt Arial bold} + P {font: 10pt Arial} + TD {font: 10pt Arial} + A {text-decoration: none; color: blue} +</STYLE> + +</HEAD> + +<BODY BGCOLOR="#FFFFFF" TEXT="#000000"> +<font face="Arial"> +<H1 style="margin-top: 0; margin-bottom: 0"><A NAME="keyboard"><font size="4"> +</font></A><I><font size="4">KEYBOARD COMMANDS</font></I></H1> +<p style="margin-top: 0; margin-bottom: 0"> </p> + +<font size="2"> + +<P style="margin-top: 0; margin-bottom: 0">Hot keys: </P> +<blockquote> + <table border="1" width="90%" id="table1"> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <B>Ctrl+O</B></font></td> + <td> + +<font size="2" face="Arial"> + + open a file</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <B>Ctrl+D</B> +</font> + </td> + <td> + +<font size="2" face="Arial"> + + disassemble the loaded file into IL source file</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <B>Ctrl+T</B></font></td> + <td> + +<font size="2" face="Arial"> + + dump fully expanded tree view into a text file</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <B>Ctrl+M</B></font></td> + <td> + +<font size="2" face="Arial"> + + show metadata info in a disassembly window (advanced mode only)</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <B>Ctrl+X</B></font></td> + <td> + +<font size="2" face="Arial"> + + exit</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <B>F1</B> or + <B>Alt+H</B></font></td> + <td> + +<font size="2" face="Arial"> + + Show this help window</font></td> + </tr> + </table> +</blockquote> +<P style="margin-top: 0; margin-bottom: 0"> </P> + +<p style="margin-top: 0; margin-bottom: 0"></p> + +<P style="margin-top: 0; margin-bottom: 0">In tree view:</P> + +<blockquote> + <table border="1" width="90%" id="table2"> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <b>Enter</b></font></td> + <td> + +<font size="2" face="Arial"> + + similar to double clicking (see above)</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <b>Cursor right</b></font></td> + <td> + +<font size="2" face="Arial"> + + expand subtree</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <b>Cursor left</b></font></td> + <td> + +<font size="2" face="Arial"> + + collapse subtree</font></td> + </tr> + <tr> + <td width="123"> + +<font size="2" face="Arial"> + + <b>Cursor up/down</b></font></td> + <td> + +<font size="2" face="Arial"> + + select previous/next item</font></td> + </tr> + </table> +</blockquote> +</font> +</font> +</BODY> +</HTML> diff --git a/src/ildasm/html/menu_options.htm b/src/ildasm/html/menu_options.htm new file mode 100644 index 0000000000..d96f59acfa --- /dev/null +++ b/src/ildasm/html/menu_options.htm @@ -0,0 +1,324 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<HTML> +<HEAD> +<META HTTP-EQUIV="Content-Type" Content="text/html; charset=Windows-1252"> +<TITLE>Menu Options</TITLE> + +<STYLE> + BODY {background: white; color: black} + h3 {font: 8pt Arial bold} + P {font: 10pt Arial} + blockquote {text-indent: 0%} + TD {font: 10pt Arial} + A {text-decoration: none; color: blue} +</STYLE> + +</HEAD> + +<BODY BGCOLOR="#FFFFFF" TEXT="#000000"> +<font face="Arial"> +<P style="margin-top: 0; margin-bottom: 0"><A NAME="menu_options"></A><B><I><font size="4">MENU OPTIONS</font></I></B></P> + +<P style="margin-top: 0; margin-bottom: 0"> </P> +<P style="margin-top: 0; margin-bottom: 0"><B>File</B> (Alt+F)</P> +<font size="2"> +<blockquote> + <table border="1" width="90%" id="table1"> + <tr> + <td width="155" valign="top"> +<font size="2" face="Arial"> + <B>Open</B> (Ctrl+O)</font></td> + <td> +<font size="2" face="Arial"> + select a PE file to open</font></td> + </tr> + <tr> + <td width="155" valign="top"> +<font size="2" face="Arial"> + <B>Dump</B> (Ctrl+D)</font></td> + <td> +<font size="2" face="Arial"> + dump the current PE file to an IL source file</font></td> + </tr> + <tr> + <td width="155" valign="top"> +<font size="2" face="Arial"> + <B>Dump TreeView</B> (Ctrl+T)</font></td> + <td> +<font size="2" face="Arial"> + dump the fully expanded tree view of current PE file to a text file</font></td> + </tr> + <tr> + <td width="155" valign="top"> +<font size="2" face="Arial"> + <B>Exit</B> (Ctrl+X)</font></td> + <td> +<font size="2" face="Arial"> + close the current PE file and exit</font></td> + </tr> + </table> +</blockquote> +</font> +<p style="margin-top: 0; margin-bottom: 0"> +</P> + +<P style="margin-top: 0; margin-bottom: 0"> </P> +<P style="margin-top: 0; margin-bottom: 0"><B>View</B> (Alt+V)</P> + +<font size="2"> +<blockquote> + <table border="1" width="90%" id="table2"> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Set Fonts</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + set the fonts for tree view and disassembly windows. Default fonts + are MS Sans Serif 8 for tree view and Courier 10 for Disassembly + windows</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Sort by name</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) sort the items in tree view by name</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show Public</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show or dump the items having public accessibility</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show Private</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show or dump the items having private accessibility</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show Family</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show or dump the items having family accessibility</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show Assembly</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show or dump the items having assembly accessibility</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show FamANDAssem</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show or dump the items having family-and-assembly + accessibility</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show FamORAssem</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show or dump the items having family-or-assembly + accessibility</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show PrivateScope</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show or dump the items having private scope accessibility</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show Member Types</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show types of members ('method','field',etc.) in tree view nodes</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show bytes</B> +</font> + </td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show the actual IL code in hexadecimal (as comments) when + disassembling the methods</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show token values</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show token values in hexadecimal (as comments)</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Show source lines</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) show the original source code (as comments, if the original + source is available)</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Quote all names</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) include all names in single quotes (when off, only illegal + names are quoted)</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Expand try/catch</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + (on/off) present SEH clauses in expanded form when possible (<B>try { ... } catch ExceptionClass { ... }</B>)</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>COR Header</B></font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + show contents of COR header in a disassembly window"</font></td> + </tr> + <tr> + <td width="155" valign="top"> + +<font size="2" face="Arial"> + <B>Statistics</B> <br> + (advanced mode only)</font></td> + <td colspan="2" valign="top"> + +<font size="2" face="Arial"> + show PE file statistics in a disassembly window</font></td> + </tr> + <tr> + <td width="155" rowspan="6" valign="top"> + +<font size="2" face="Arial"> + <B>MetaInfo</B> <br> + (advanced mode only)</font></td> + <td width="16%" valign="top"> + +<font size="2" face="Arial"> + <B>Header</B> +</font> + </td> + <td valign="top"> + +<font size="2" face="Arial"> + (on/off) show metadata info as header summary</font></td> + </tr> + <tr> + <td width="16%" valign="top"> + +<font size="2" face="Arial"> + <B>More HEX</B></font></td> + <td valign="top"> + +<font size="2" face="Arial"> + (on/off) show token and attribute values (in hexadecimal) in + metadata info</font></td> + </tr> + <tr> + <td width="16%" valign="top"> + +<font size="2" face="Arial"> + <B>CSV</B></font></td> + <td valign="top"> + +<font size="2" face="Arial"> + (on/off) show metadata info as comma-separated values</font></td> + </tr> + <tr> + <td width="16%" valign="top"> + +<font size="2" face="Arial"> + <B>Unresolved ext</B></font></td> + <td valign="top"> + +<font size="2" face="Arial"> + (on/off) add list of unresolved external references to metadata info</font></td> + </tr> + <tr> + <td width="16%" valign="top"> + +<font size="2" face="Arial"> + <B>Validate</B></font></td> + <td valign="top"> + +<font size="2" face="Arial"> + (on/off) show metadata validation results</font></td> + </tr> + <tr> + <td width="16%" valign="top"> + +<font size="2" face="Arial"> + <B>Show!</B> (Ctrl+M)</font></td> + <td valign="top"> + +<font size="2" face="Arial"> + show the metadata info in a disassembly window</font></td> + </tr> + </table> +</blockquote> +</font> +</font> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/ildasm/html/tree_view_icons.htm b/src/ildasm/html/tree_view_icons.htm new file mode 100644 index 0000000000..d39e7e811d --- /dev/null +++ b/src/ildasm/html/tree_view_icons.htm @@ -0,0 +1,102 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<HTML> +<HEAD> +<META HTTP-EQUIV="Content-Type" Content="text/html; charset=Windows-1252"> +<TITLE>Tree View Icons</TITLE> + +<STYLE> + BODY {background: white; color: black} + h3 {font: 8pt Arial bold} + P {font: 10pt Arial} + TD {font: 10pt Arial} + A {text-decoration: none; color: blue} +</STYLE> + +</HEAD> + +<BODY BGCOLOR="#FFFFFF" TEXT="#000000"> +<font face="Arial"> + +<H1 style="margin-top: 0; margin-bottom: 0"><A NAME="tree_view_icons"> +</A><I><font size="4">TREE VIEW ICONS</font></I></H1> +<p style="margin-top: 0; margin-bottom: 0"> </p> + +<table border="1" width="82%" id="table1" cellpadding="3" cellspacing="3" > +<font size="2"> + <tr> + <td width="148" valign="top"><b>Namespace</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/namespace.gif" width="15" height="15"></td> + <td width="321" valign="top">(Blue shield)</td> + </tr> + <tr> + <td width="148" valign="top"><b>Class</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/class.gif" width="15" height="15"></td> + <td width="321" valign="top">(Blue rectangle with three outputs)</td> + </tr> + <tr> + <td width="148" valign="top"><b>Interface</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/interface.gif" width="15" height="15"></td> + <td width="321" valign="top">(Blue rectangle with three outputs marked 'I')</td> + </tr> + <tr> + <td width="148" valign="top"><b>Value Class</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/value_class.gif" width="15" height="15"></td> + <td width="321" valign="top">(Brown rectangle with three outputs)</td> + </tr> + <tr> + <td width="148" valign="top"><b>Enum</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/enum.gif" width="15" height="15"></td> + <td width="321" valign="top">(Brown rectangle with three outputs marked 'E')</td> + </tr> + <tr> + <td width="148" valign="top"><b>Method</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/method.gif" width="15" height="15"></td> + <td width="321" valign="top">(Magenta rectangle)</td> + </tr> + <tr> + <td width="148" valign="top"><b>Static method</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/static_method.gif" width="15" height="15"></td> + <td width="321" valign="top">(Magenta rectangle marked 'S')</td> + </tr> + <tr> + <td width="148" valign="top"><b>Field</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/field.gif" width="15" height="15"></td> + <td width="321" valign="top">(Cyan diamond)</td> + </tr> + <tr> + <td width="148" valign="top"><b>Static field</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/static_field.gif" width="15" height="15"></td> + <td width="321" valign="top">(Cyan diamond marked 'S')</td> + </tr> + <tr> + <td width="148" valign="top"><b>Event</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/event.gif" width="15" height="15"></td> + <td width="321" valign="top">(Green point-down triangle)</td> + </tr> + <tr> + <td width="148" valign="top"><b>Property</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/property.gif" width="15" height="15"></td> + <td width="321" valign="top">(Red point-up triangle)</td> + </tr> + <tr> + <td width="148" valign="top"><b>Manifest or a class info item</b></td> + <td align="center" valign="top"> + <img border="0" src="tree_view_icons_files/manifest_classinfo.GIF" width="15" height="15"></td> + <td width="321" valign="top">(Red point-right triangle)</td> + </tr> +</font></table> + +</font> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/ildasm/html/tree_view_icons_files/class.gif b/src/ildasm/html/tree_view_icons_files/class.gif Binary files differnew file mode 100644 index 0000000000..53d1494a33 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/class.gif diff --git a/src/ildasm/html/tree_view_icons_files/enum.gif b/src/ildasm/html/tree_view_icons_files/enum.gif Binary files differnew file mode 100644 index 0000000000..af7a94ee0b --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/enum.gif diff --git a/src/ildasm/html/tree_view_icons_files/event.gif b/src/ildasm/html/tree_view_icons_files/event.gif Binary files differnew file mode 100644 index 0000000000..00de688ab8 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/event.gif diff --git a/src/ildasm/html/tree_view_icons_files/field.gif b/src/ildasm/html/tree_view_icons_files/field.gif Binary files differnew file mode 100644 index 0000000000..0b6ed0a74b --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/field.gif diff --git a/src/ildasm/html/tree_view_icons_files/interface.gif b/src/ildasm/html/tree_view_icons_files/interface.gif Binary files differnew file mode 100644 index 0000000000..21664cc715 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/interface.gif diff --git a/src/ildasm/html/tree_view_icons_files/manifest_classinfo.GIF b/src/ildasm/html/tree_view_icons_files/manifest_classinfo.GIF Binary files differnew file mode 100644 index 0000000000..8811686023 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/manifest_classinfo.GIF diff --git a/src/ildasm/html/tree_view_icons_files/manifest_classinfo.jpg b/src/ildasm/html/tree_view_icons_files/manifest_classinfo.jpg Binary files differnew file mode 100644 index 0000000000..8a752429eb --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/manifest_classinfo.jpg diff --git a/src/ildasm/html/tree_view_icons_files/manifest_classinfo.png b/src/ildasm/html/tree_view_icons_files/manifest_classinfo.png Binary files differnew file mode 100644 index 0000000000..a68d41dd02 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/manifest_classinfo.png diff --git a/src/ildasm/html/tree_view_icons_files/method.gif b/src/ildasm/html/tree_view_icons_files/method.gif Binary files differnew file mode 100644 index 0000000000..d96cfe4e0b --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/method.gif diff --git a/src/ildasm/html/tree_view_icons_files/namespace.gif b/src/ildasm/html/tree_view_icons_files/namespace.gif Binary files differnew file mode 100644 index 0000000000..4001293dc0 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/namespace.gif diff --git a/src/ildasm/html/tree_view_icons_files/property.gif b/src/ildasm/html/tree_view_icons_files/property.gif Binary files differnew file mode 100644 index 0000000000..08edbf854c --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/property.gif diff --git a/src/ildasm/html/tree_view_icons_files/static_field.gif b/src/ildasm/html/tree_view_icons_files/static_field.gif Binary files differnew file mode 100644 index 0000000000..d8d6ff3ca3 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/static_field.gif diff --git a/src/ildasm/html/tree_view_icons_files/static_method.gif b/src/ildasm/html/tree_view_icons_files/static_method.gif Binary files differnew file mode 100644 index 0000000000..5d982e1fc8 --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/static_method.gif diff --git a/src/ildasm/html/tree_view_icons_files/value_class.gif b/src/ildasm/html/tree_view_icons_files/value_class.gif Binary files differnew file mode 100644 index 0000000000..d4546f510f --- /dev/null +++ b/src/ildasm/html/tree_view_icons_files/value_class.gif diff --git a/src/ildasm/ildasm.chm b/src/ildasm/ildasm.chm Binary files differnew file mode 100644 index 0000000000..166b1ca936 --- /dev/null +++ b/src/ildasm/ildasm.chm diff --git a/src/ildasm/ildasm.hhp b/src/ildasm/ildasm.hhp new file mode 100644 index 0000000000..71d47f5ff7 --- /dev/null +++ b/src/ildasm/ildasm.hhp @@ -0,0 +1,36 @@ +[OPTIONS] +Binary Index=No +Compatibility=1.1 or later +Compiled file=ildasm.chm +Contents file=dasmhlp.hhc +Default Font=Arial,8,0 +Default Window=Main +Default topic=html\menu_options.htm +Display compile progress=No +Full-text search=Yes +Language=0x409 English (United States) +Title=MSIL Disassembler Help + +[WINDOWS] +Main="MSIL Disassembler Help","dasmhlp.hhc",,"html\menu_options.htm","html\menu_options.htm",,,,,0x42520,185,0x3006,[253,102,1070,702],,0x8,,,,,0 + + +[FILES] +html\clicking.htm +html\keyboard.htm +html\menu_options.htm +html\tree_view_icons.htm +ildasm.hhp +map.h + +[ALIAS] +CLICKING=html\clicking.htm +KEYBOARD=html\keyboard.htm +MENU_OPTIONS=html\menu_options.htm +TREE_VIEW_ICONS=html\tree_view_icons.htm + +[MAP] +#include map.h + +[INFOTYPES] + diff --git a/src/ildasm/ildasmpch.cpp b/src/ildasm/ildasmpch.cpp new file mode 100644 index 0000000000..5ca4dcfefb --- /dev/null +++ b/src/ildasm/ildasmpch.cpp @@ -0,0 +1,8 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// This is just to build the PCH for ildasm +#include "ildasmpch.h" diff --git a/src/ildasm/ildasmpch.h b/src/ildasm/ildasmpch.h new file mode 100644 index 0000000000..757e9111d3 --- /dev/null +++ b/src/ildasm/ildasmpch.h @@ -0,0 +1,26 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#if !defined(_ILDASMPCH_H) +#define _ILDASMPCH_H + +#define OEMRESOURCE +#define INITGUID + +#include <windows.h> +#include <cor.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <winuser.h> +#include <commctrl.h> +#include <commdlg.h> +#include <richedit.h> +#include <shellapi.h> +#include <htmlhelp.h> +#include <conio.h> + +#endif diff --git a/src/ildasm/map.h b/src/ildasm/map.h new file mode 100644 index 0000000000..21fcc0da71 --- /dev/null +++ b/src/ildasm/map.h @@ -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 MENU_OPTIONS 1 +#define TREE_VIEW_ICONS 2 +#define CLICKING 3 +#define KEYBOARD 4 diff --git a/src/ildasm/method.bmp b/src/ildasm/method.bmp Binary files differnew file mode 100644 index 0000000000..b76bb93ef7 --- /dev/null +++ b/src/ildasm/method.bmp diff --git a/src/ildasm/methodg.bmp b/src/ildasm/methodg.bmp Binary files differnew file mode 100644 index 0000000000..dfa4c68c10 --- /dev/null +++ b/src/ildasm/methodg.bmp diff --git a/src/ildasm/namespace.bmp b/src/ildasm/namespace.bmp Binary files differnew file mode 100644 index 0000000000..6ac839ee65 --- /dev/null +++ b/src/ildasm/namespace.bmp diff --git a/src/ildasm/prop.bmp b/src/ildasm/prop.bmp Binary files differnew file mode 100644 index 0000000000..857e69c3fe --- /dev/null +++ b/src/ildasm/prop.bmp diff --git a/src/ildasm/rcdll/ildasmrc.nativeproj b/src/ildasm/rcdll/ildasmrc.nativeproj new file mode 100644 index 0000000000..11066deba8 --- /dev/null +++ b/src/ildasm/rcdll/ildasmrc.nativeproj @@ -0,0 +1,18 @@ +<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>ildasmrc</OutputName> + <TargetType>DYNLINK</TargetType> + <LinkSubsystem>windows</LinkSubsystem> + <RCAdditionalOptions>$(RCAdditionalOptions) -r</RCAdditionalOptions> + <LinkResourceOnlyDll>true</LinkResourceOnlyDll> + </PropertyGroup> + <!--Leaf Project Items--> + <ItemGroup> + <RCResourceFile Include="..\dasm.rc" /> + </ItemGroup> + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> diff --git a/src/ildasm/redarrow.bmp b/src/ildasm/redarrow.bmp Binary files differnew file mode 100644 index 0000000000..ce94dc8fb2 --- /dev/null +++ b/src/ildasm/redarrow.bmp diff --git a/src/ildasm/resource.h b/src/ildasm/resource.h new file mode 100644 index 0000000000..bf993b6dcf --- /dev/null +++ b/src/ildasm/resource.h @@ -0,0 +1,325 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by dasm.rc +// + +#include <copyrightstring.h> + +#define IDS_FILE 1 +#define IDS_VIEW 2 +#define IDS_HELP 3 +#define IDS_OPEN 4 +#define IDS_DUMP 5 +#define IDS_DUMPTREE 6 +#define IDS_EXIT 7 +#define IDS_FONTS 8 +#define IDS_FONT_TREE 9 +#define IDS_FONT_DASM 10 +#define IDS_SORT_BY_NAME 11 +#define IDS_SHOW_PUB 12 +#define IDS_SHOW_PRIV 13 +#define IDS_SHOW_FAM 14 +#define IDS_SHOW_ASM 15 +#define IDS_SHOW_FAA 16 +#define IDS_SHOW_FOA 17 +#define IDS_SHOW_PSCOPE 18 +#define IDS_FULL_INFO 19 +#define IDS_BYTES 20 +#define IDS_TOKENS 21 +#define IDS_SOURCELINES 22 +#define IDS_QUOTEALLNAMES 23 +#define IDS_EXPANDTRY 24 +#define IDS_SHOW_HEADER 25 +#define IDS_SHOW_STAT 26 +#define IDS_METAINFO 27 +#define IDS_MI_HEADER 28 +#define IDS_MI_HEX 29 +#define IDS_MI_CSV 30 +#define IDS_MI_UNREX 31 +#define IDS_MI_DEBUG 32 +#define IDS_MI_SCHEMA 33 +#define IDS_MI_RAW 34 +#define IDS_MI_HEAPS 35 +#define IDS_MI_VALIDATE 36 +#define IDS_SHOW_METAINFO 37 +#define IDS_ABOUT 38 +#define IDS_ABOUT_COPYRIGHTINFO 39 +#define IDS_PRODUCTNAME 40 +#define IDS_MAINWINDOWCAPTION 41 +#define IDS_MAINWINDOWCAPTIONAPPEND 42 +#define IDS_NETHEADER 43 +#define IDS_STATISTICS 44 +#define IDS_METAINFOTEXT 45 +#define IDS_FIND 46 +#define IDS_FINDNEXT 47 +#define IDS_RTL 48 +#define IDS_TREEVIEWFCN 49 +#define IDS_CAVERBAL 50 +#define IDS_DUMPRTF 51 + +#define IDI_ICON2 136 +#define IDD_DIALOG1 137 +#define IDD_ABOUT 149 +#define IDR_MAINMENU 149 +#define IDI_ICON1 150 + +#define IDS_USAGE_TITLE 200 +#define IDS_USAGE_01 IDS_USAGE_TITLE + 1 +#define IDS_USAGE_02 IDS_USAGE_01 + 1 +#define IDS_USAGE_03 IDS_USAGE_02 + 1 +#define IDS_USAGE_04 IDS_USAGE_03 + 1 +#define IDS_USAGE_04A IDS_USAGE_04 + 1 +#define IDS_USAGE_04B IDS_USAGE_04A + 1 +#define IDS_USAGE_05 IDS_USAGE_04B + 1 +#ifdef OWNER_OPTION_ENABLED +#define IDS_USAGE_06 IDS_USAGE_05 + 1 +#else +#define IDS_USAGE_06 IDS_USAGE_05 +#endif +#define IDS_USAGE_07 IDS_USAGE_06 + 1 +#define IDS_USAGE_08 IDS_USAGE_07 + 1 +#define IDS_USAGE_09 IDS_USAGE_08 + 1 +#define IDS_USAGE_10 IDS_USAGE_09 + 1 +#ifdef _DEBUG +#define IDS_USAGE_10A IDS_USAGE_10 + 1 +#else +#define IDS_USAGE_10A IDS_USAGE_10 +#endif +#define IDS_USAGE_11 IDS_USAGE_10A + 1 +#define IDS_USAGE_12 IDS_USAGE_11 + 1 +#define IDS_USAGE_13 IDS_USAGE_12 + 1 +#define IDS_USAGE_14 IDS_USAGE_13 + 1 +#define IDS_USAGE_15 IDS_USAGE_14 + 1 +#define IDS_USAGE_15A IDS_USAGE_15 + 1 +#define IDS_USAGE_15B IDS_USAGE_15A + 1 +#define IDS_USAGE_16 IDS_USAGE_15B + 1 +#define IDS_USAGE_17 IDS_USAGE_16 + 1 +#define IDS_USAGE_18 IDS_USAGE_17 + 1 +#define IDS_USAGE_19 IDS_USAGE_18 + 1 +#define IDS_USAGE_20 IDS_USAGE_19 + 1 +#define IDS_USAGE_21 IDS_USAGE_20 + 1 +#define IDS_USAGE_21A IDS_USAGE_21 + 1 +#define IDS_USAGE_21B IDS_USAGE_21A + 1 +#define IDS_USAGE_21C IDS_USAGE_21B + 1 +#define IDS_USAGE_22 IDS_USAGE_21C + 1 +#define IDS_USAGE_23 IDS_USAGE_22 + 1 +#define IDS_USAGE_24 IDS_USAGE_23 + 1 +#define IDS_USAGE_25 IDS_USAGE_24 + 1 +#define IDS_USAGE_26 IDS_USAGE_25 + 1 +#define IDS_USAGE_27 IDS_USAGE_26 + 1 +#define IDS_USAGE_28 IDS_USAGE_27 + 1 +#define IDS_USAGE_29 IDS_USAGE_28 + 1 +#define IDS_USAGE_30 IDS_USAGE_29 + 1 +#define IDS_USAGE_31 IDS_USAGE_30 + 1 +#define IDS_USAGE_32 IDS_USAGE_31 + 1 +#define IDS_USAGE_33 IDS_USAGE_32 + 1 +#define IDS_USAGE_34 IDS_USAGE_33 + 1 +#define IDS_USAGE_35 IDS_USAGE_34 + 1 +#define IDS_USAGE_36 IDS_USAGE_35 + 1 +#define IDS_USAGE_37 IDS_USAGE_36 + 1 +#define IDS_USAGE_38 IDS_USAGE_37 + 1 +#define IDS_USAGE_39 IDS_USAGE_38 + 1 +#define IDS_USAGE_40 IDS_USAGE_39 + 1 +#define IDS_USAGE_41 IDS_USAGE_40 + 1 +#define IDS_USAGE_42 IDS_USAGE_41 + 1 +#define IDS_USAGE_43 IDS_USAGE_42 + 1 + +#define IDB_CLASS 300 +#define IDB_EVENT 301 +#define IDB_METHOD 302 +#define IDB_NAMESPACE 303 +#define IDB_FIELD 304 +#define IDB_PROP 305 +#define IDB_STATICMETHOD 306 +#define IDB_STATICFIELD 307 +#define IDB_REDARROW 308 +#define IDB_CLASSENUM 309 +#define IDB_CLASSINT 310 +#define IDB_CLASSVAL 311 + +#define IDB_CLASS_GEN 312 +#define IDB_METHOD_GEN 313 +#define IDB_STATICMETHOD_GEN 314 +#define IDB_CLASSENUM_GEN 315 +#define IDB_CLASSINT_GEN 316 +#define IDB_CLASSVAL_GEN 317 + +#define IDS_E_INITLDR 401 +#define IDS_E_FILEOPEN 402 +#define IDS_E_NOCORHDR 403 +#define IDS_E_BADCORHDR 404 +#define IDS_E_OPENMD 405 +#define IDS_E_COPYRIGHT 406 +#define IDS_E_DASMABORT 407 +#define IDS_E_DASMOK 408 +#define IDS_E_PARTDASM 409 +#define IDS_E_INSTRDT 410 +#define IDS_E_NOCOMPR 411 +#define IDS_E_CLSENUM 412 +#define IDS_E_SELFNSTD 413 +#define IDS_E_NOENCLOS 414 +#define IDS_E_INVALIDTK 415 +#define IDS_E_UNEXPTYPE 416 +#define IDS_E_AUTOCA 417 +#define IDS_E_PARAMSEQNO 418 +#define IDS_E_METHBEG 419 +#define IDS_E_DASMERR 420 +#define IDS_E_DASMNATIVE 421 +#define IDS_E_METHODRT 422 +#define IDS_E_NORVA 423 +#define IDS_E_MEMBRENUM 424 +#define IDS_E_ODDMEMBER 425 +#define IDS_E_ENUMINIT 426 +#define IDS_E_NODATA 427 +#define IDS_E_VTFUTABLE 428 +#define IDS_E_BOGUSRVA 429 +#define IDS_E_EATJTABLE 430 +#define IDS_E_EATJSIZE 431 +#define IDS_E_RESFLAGS 432 +#define IDS_E_MIHENTRY 433 +#define IDS_E_CODEMGRTBL 434 +#define IDS_E_IMPORTDATA 435 +#define IDS_E_COMIMAGE 436 +#define IDS_E_MDDETAILS 437 +#define IDS_E_MISTART 438 +#define IDS_E_MIEND 439 +#define IDS_E_ONLYITEMS 440 +#define IDS_E_ROGUEPTR 441 +#define IDS_E_DECOMPRESS 442 +#define IDS_E_COMPRESSED 443 +#define IDS_E_CODESIZE 444 +#define IDS_E_BOGUSLVSIG 445 +#define IDS_E_INSTRDECOD 446 +#define IDS_E_INSTRTYPE 447 +#define IDS_E_ARGINDEX 448 +#define IDS_E_LVINDEX 449 +#define IDS_E_SECTHEADER 451 +#define IDS_E_BADTOKENTYPE 452 +#define IDS_E_MDAIMPORT 454 +#define IDS_E_MDAFROMMDI 455 +#define IDS_E_MDIIMPORT 456 +#define IDS_E_NOMANIFEST 457 + +#define IDS_E_MULTIPLEINPUT 458 +#define IDS_E_INVALIDOPTION 459 +#define IDS_PROGRESSBOX 460 +#define IDS_DISASSEMBLING 461 +#define IDS_PB_FILE 462 +#define IDS_PB_FILE1 463 +#define IDS_PB_TOFILE 464 +#define IDS_PB_TOFILE1 465 +#define IDS_PB_CLASSESDONE 466 +#define IDS_PB_GLOBALSDONE 467 +#define IDS_PB_CANCEL 468 +#define IDS_PB_WRITINGDATA 469 +#define IDS_W_CREATEDW32RES 470 +#define IDS_E_CORRUPTW32RES 471 +#define IDS_E_CANTOPENW32RES 472 +#define IDS_E_CANTACCESSW32RES 473 +#define IDS_CANTVIEW_TX 474 +#define IDS_CANTVIEW_HD 475 +#define IDS_ONLYPEINGUI 476 +#define IDS_BADFILETYPE 477 +#define IDS_E_CANTOPENOUT 478 +#define IDS_E_CANTCREATEPROC 479 +#define IDS_TEXTTOOLARGEFORGUI 480 +#define IDS_FILTER_IN 481 +#define IDS_FILTER_OUT 482 +#define IDS_FILTER_OUT2 483 +#define IDS_CANNOTOPENFILE 484 +#define IDS_UNABLETOREGLIBS 485 +#define IDS_ERRORREOPENINGFILE 486 +#define IDS_ASSEMNAMETOOLONG 487 +#define IDS_ASMREFNAMETOOLONG 488 +#define IDS_ERRORCAPTION 489 +#define IDS_ILDASM_TITLE 490 +#define IDS_VERSION 491 +#define IDS_W_CREATEDMRES 492 +#define IDS_E_READINGMRES 493 +#define IDS_E_SUPPRESSED 494 +#define IDS_LEGALCOPYRIGHT 495 +#define IDS_E_INVALIDRECORD 496 + +#define IDC_CHECK1 1000 +#define IDC_CHECK2 1001 +#define IDC_CHECK3 1002 +#define IDC_CHECK4 1003 +#define IDC_CHECK5 1004 +#define IDC_CHECK6 1005 +#define IDC_CHECK7 1006 +#define IDC_CHECK8 1007 +#define IDC_CHECK9 1008 +#define IDC_CHECK10 1009 +#define IDC_CHECK11 1010 +#define IDC_CHECK12 1011 +#define IDC_CHECK13 1012 +#define IDC_CHECK14 1013 +#define IDC_CHECK15 1014 +#define IDC_CHECK16 1015 +#define IDC_CHECK17 1016 +#define IDC_CHECK18 1017 +#define IDC_CHECK19 1018 +#define IDC_CHECK20 1019 +#define IDC_RADIO1 1020 +#define IDC_RADIO2 1021 +#define IDC_ABOUT_LINE1 1021 +#define ID_ABOUT_COPYRIGHTINFO 1021 +#define IDC_ABOUT_COPYRIGHTINFO 1021 +#define IDC_RADIO3 1022 +#define ID_ABOUT_OK 1022 +#define IDC_ABOUT_LINE2 1023 +#define IDC_ABOUT_PRODUCTNAME 1023 +#define IDC_ABOUT_LINE3 1024 +#define IDC_ABOUT_VERSION 1024 +#define IDC_ABOUT_LEGALCOPYRIGHT 1025 +#define ID_EXPORT 32771 +#define ID_HELP_ABOUT 32772 +#define ID_HELP_CONTENTS 32773 +#define ID_FILE_DUMP 32774 +#define ID_FILE_DUMP_TREEVIEW 32775 +#define ID_FILE_EXIT 32776 +#define ID_VIEW_SORTBYNAME 32778 +#define ID_VIEW_SHOWPUBLIC 32779 +#define ID_VIEW_SHOWPRIVATE 32780 +#define ID_VIEW_SHOWFAMILY 32781 +#define ID_VIEW_SHOWASSEMBLY 32782 +#define ID_VIEW_SHOWFAMANDASSEM 32783 +#define ID_VIEW_SHOWFAMORASSEM 32784 +#define ID_VIEW_SHOWPRIVATESCOPE 32785 +#define ID_VIEW_SHOWMEMBERTYPES 32786 +#define ID_VIEW_SHOWBYTES 32787 +#define ID_VIEW_SHOWTOKENVALUES 32788 +#define ID_VIEW_SHOWSOURCELINES 32789 +#define ID_VIEW_QUOTEALLNAMES 32790 +#define ID_VIEW_EXPANDTRYCATCH 32791 +#define ID_VIEW_NETRUNTIMEHEADER 32792 +#define ID_VIEW_STATISTICS 32793 +#define ID_VIEW_SETFONTS_TREEVIEW 32795 +#define ID_VIEW_SETFONTS_DISASSEMBLY 32796 +#define ID_VIEW_METAINFO_HEADER 32797 +#define ID_VIEW_METAINFO_MOREHEX 32798 +#define ID_VIEW_METAINFO_CSV 32799 +#define ID_VIEW_METAINFO_UNRESOLVEDEXT 32800 +#define ID_VIEW_METAINFO_DEBUG 32801 +#define ID_VIEW_METAINFO_SCHEMA 32802 +#define ID_VIEW_METAINFO_RAW 32803 +#define ID_VIEW_METAINFO_HEAPS 32804 +#define ID_VIEW_METAINFO_VALIDATE 32805 +#define ID_VIEW_METAINFO_SHOW 32806 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 151 +#define _APS_NEXT_COMMAND_VALUE 32774 +#define _APS_NEXT_CONTROL_VALUE 1026 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/ildasm/staticfield.bmp b/src/ildasm/staticfield.bmp Binary files differnew file mode 100644 index 0000000000..70edc432c1 --- /dev/null +++ b/src/ildasm/staticfield.bmp diff --git a/src/ildasm/staticmethod.bmp b/src/ildasm/staticmethod.bmp Binary files differnew file mode 100644 index 0000000000..bc87d243ae --- /dev/null +++ b/src/ildasm/staticmethod.bmp diff --git a/src/ildasm/staticmethodg.bmp b/src/ildasm/staticmethodg.bmp Binary files differnew file mode 100644 index 0000000000..fedc1c56da --- /dev/null +++ b/src/ildasm/staticmethodg.bmp diff --git a/src/ildasm/util.hpp b/src/ildasm/util.hpp new file mode 100644 index 0000000000..fdcc8a8268 --- /dev/null +++ b/src/ildasm/util.hpp @@ -0,0 +1,23 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +// +// util.hpp +// +// Miscellaneous useful functions +// +#ifndef _H_UTIL +#define _H_UTIL + +#include <objbase.h> + +#if defined(_DEBUG) +#include <crtdbg.h> +#undef _ASSERTE // utilcode defines a custom _ASSERTE +#endif + +#include "utilcode.h" + +#endif /* _H_UTIL */ diff --git a/src/ildasm/windasm.cpp b/src/ildasm/windasm.cpp new file mode 100644 index 0000000000..43732f939d --- /dev/null +++ b/src/ildasm/windasm.cpp @@ -0,0 +1,698 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +/************************************************************************************************ + * * + * File: winmain.cpp * + * * + * Purpose: Main program for graphic COM+ 2.0 disassembler ILDASM.exe * + * * + ************************************************************************************************/ +#include "ildasmpch.h" + +#include "dynamicarray.h" + +#define DO_DASM_GUI +#include "dasmgui.h" +#include "dasmenum.hpp" +#include "dis.h" +#include <ndpversion.h> +#include "resource.h" + +#include "new.hpp" + +#define MODE_DUMP_ALL 0 +#define MODE_DUMP_CLASS 1 +#define MODE_DUMP_CLASS_METHOD 2 +#define MODE_DUMP_CLASS_METHOD_SIG 3 +#define MODE_GUI 4 + +// All externs are defined in DASM.CPP +extern BOOL g_fDumpIL; +extern BOOL g_fDumpHeader; +extern BOOL g_fDumpAsmCode; +extern BOOL g_fDumpTokens; +extern BOOL g_fDumpStats; +extern BOOL g_fDumpClassList; +extern BOOL g_fDumpTypeList; +extern BOOL g_fDumpSummary; +extern BOOL g_fDecompile; // still in progress +extern BOOL g_fShowRefs; + +extern BOOL g_fDumpToPerfWriter; + +extern BOOL g_fShowBytes; +extern BOOL g_fShowSource; +extern BOOL g_fInsertSourceLines; +extern BOOL g_fTryInCode; +extern BOOL g_fQuoteAllNames; +extern BOOL g_fShowProgressBar; +extern HINSTANCE g_hResources; +extern BOOL g_fTDC; +extern BOOL g_fShowCA; +extern BOOL g_fCAVerbal; + +extern char g_pszClassToDump[]; +extern char g_pszMethodToDump[]; +extern char g_pszSigToDump[]; + +extern char g_szAsmCodeIndent[]; + +extern DWORD g_Mode; + +extern char g_szInputFile[]; // in UTF-8 +extern WCHAR g_wszFullInputFile[]; // in UTF-16 +extern char g_szOutputFile[]; // in UTF-8 +extern char* g_pszObjFileName; +extern FILE* g_pFile; + +extern BOOL g_fLimitedVisibility; +#if defined(_DEBUG) && defined(FEATURE_PREJIT) +extern BOOL g_fNGenNativeMetadata; +#endif +extern BOOL g_fHidePub; +extern BOOL g_fHidePriv; +extern BOOL g_fHideFam; +extern BOOL g_fHideAsm; +extern BOOL g_fHideFAA; +extern BOOL g_fHideFOA; +extern BOOL g_fHidePrivScope; +extern BOOL g_fProject; + +extern unsigned g_uCodePage; +extern unsigned g_uConsoleCP; +extern BOOL g_fForwardDecl; +extern BOOL g_fUseProperName; + +#include "../tools/metainfo/mdinfo.h" +extern BOOL g_fDumpMetaInfo; +extern ULONG g_ulMetaInfoFilter; +HINSTANCE g_hInstance; +HANDLE hConsoleOut=NULL; +HANDLE hConsoleErr=NULL; +// These are implemented in DASM.CPP: +BOOL Init(); +void Uninit(); +void Cleanup(); +void DumpMetaInfo(__in __nullterminated const WCHAR* pszFileName, __in __nullterminated const char* pszObjFileName, void* GUICookie); +FILE* OpenOutput(__in __nullterminated const char* szFileName); + +// Do we only view an IL-dasm window in GUI mode? +// TRUE when we're in GUI mode and we specified a particular method from the cmd line +BOOL IsGuiILOnly() +{ + return (g_Mode & MODE_GUI) && (g_pszMethodToDump[0] != 0); +} + +void PrintLogo() +{ + printf("Microsoft (R) .NET Framework IL Disassembler. Version " VER_FILEVERSION_STR); + printf("\n%S\n\n", RstrW(IDS_LEGALCOPYRIGHT_LOGO)); +} +void SyntaxCon() +{ + DWORD l; + + for(l=IDS_USAGE_01; l<= IDS_USAGE_23; l++) printf(RstrANSI(l)); + if(g_fTDC) + { + for(l=IDS_USAGE_24; l<= IDS_USAGE_32; l++) printf(RstrANSI(l)); + for(l=IDS_USAGE_34; l<= IDS_USAGE_36; l++) printf(RstrANSI(l)); + for(l=IDS_USAGE_37; l<= IDS_USAGE_39; l++) printf(RstrANSI(l)); + } + else printf(RstrANSI(IDS_USAGE_40)); + for(l=IDS_USAGE_41; l<= IDS_USAGE_42; l++) printf(RstrANSI(l)); + +} + +char* CheckForDQuotes(__inout __nullterminated char* sz) +{ + char* ret = sz; + if(*sz == '"') + { + ret++; + sz[strlen(sz)-1] = 0; + } + return ret; +} + +char* EqualOrColon(__in __nullterminated char* szArg) +{ + char* pchE = strchr(szArg,'='); + char* pchC = strchr(szArg,':'); + char* ret; + if(pchE == NULL) ret = pchC; + else if(pchC == NULL) ret = pchE; + else ret = (pchE < pchC)? pchE : pchC; + return ret; +} + +void GetInputFileFullPath() +{ + // We need the input file's full path to make uses of it later, despite changing CurrentDirectory + + // First, convert back up to UTF16 + DWORD len = (DWORD) strlen(g_szInputFile) + 16; + WCHAR* wzArg = new WCHAR[len]; + memset(wzArg, 0, len * sizeof(WCHAR)); + WszMultiByteToWideChar(g_uConsoleCP, 0, g_szInputFile, -1, wzArg, len); + + // Get the full path + len = GetFullPathName(wzArg, MAX_PATH, g_wszFullInputFile, NULL); + VDELETE(wzArg); +} + +int ProcessOneArg(__in __nullterminated char* szArg, __out char** ppszObjFileName) +{ + char szOpt[128]; + if(strlen(szArg) == 0) return 0; + if ((strcmp(szArg, "/?") == 0) || (strcmp(szArg, "-?") == 0)) return 1; + + if((szArg[0] == '/') || (szArg[0] == '-')) + { + strncpy_s(szOpt,128, &szArg[1],10); + szOpt[3] = 0; + if (_stricmp(szOpt, "dec") == 0) + { + g_fDecompile = TRUE; + } + else if (_stricmp(szOpt, "hea") == 0) + { + g_fDumpHeader = TRUE; + } + else if (_stricmp(szOpt, "adv") == 0) + { + g_fTDC = TRUE; + } + else if (_stricmp(szOpt, "tok") == 0) + { + g_fDumpTokens = TRUE; + } + else if (_stricmp(szOpt, "noi") == 0) + { + g_fDumpAsmCode = FALSE; + } + else if (_stricmp(szOpt, "noc") == 0) + { + g_fShowCA = FALSE; + } + else if (_stricmp(szOpt, "cav") == 0) + { + g_fCAVerbal = TRUE; + } + else if (_stricmp(szOpt, "not") == 0) + { + g_fTryInCode = FALSE; + } + else if (_stricmp(szOpt, "raw") == 0) + { + g_fTryInCode = FALSE; + } + else if (_stricmp(szOpt, "byt") == 0) + { + g_fShowBytes = TRUE; + } + else if (_stricmp(szOpt, "sou") == 0) + { + g_fShowSource = TRUE; + } + else if (_stricmp(szOpt, "lin") == 0) + { + g_fInsertSourceLines = TRUE; + } + else if ((_stricmp(szOpt, "sta") == 0)&&g_fTDC) + { + g_fDumpStats = g_fTDC; + } + else if ((_stricmp(szOpt, "cla") == 0)&&g_fTDC) + { + g_fDumpClassList = g_fTDC; + } + else if (_stricmp(szOpt, "typ") == 0) + { + g_fDumpTypeList = TRUE; + } + else if (_stricmp(szOpt, "sum") == 0) + { + g_fDumpSummary = TRUE; + } + else if (_stricmp(szOpt, "per") == 0) + { + g_fDumpToPerfWriter = TRUE; + } + else if (_stricmp(szOpt, "for") == 0) + { + g_fForwardDecl = TRUE; + } + else if (_stricmp(szOpt, "ref") == 0) + { + g_fShowRefs = TRUE; + } + else if (_stricmp(szOpt, "pub") == 0) + { + g_fLimitedVisibility = TRUE; + g_fHidePub = FALSE; + } +#if defined(_DEBUG) && defined(FEATURE_PREJIT) + else if (_stricmp(szOpt, "nat") == 0) + { + g_fNGenNativeMetadata = TRUE; + } +#endif + else if (_stricmp(szOpt, "pre") == 0) + { + //g_fPrettyPrint = TRUE; + } + else if (_stricmp(szOpt, "pro") == 0) + { + g_fProject = TRUE; + } + else if (_stricmp(szOpt, "vis") == 0) + { + char *pc = EqualOrColon(szArg); + char *pStr; + if(pc == NULL) return -1; + do { + pStr = pc+1; + pStr = CheckForDQuotes(pStr); + if((pc = strchr(pStr,'+'))) *pc=0; + if (!_stricmp(pStr,"pub")) g_fHidePub = FALSE; + else if(!_stricmp(pStr,"pri")) g_fHidePriv = FALSE; + else if(!_stricmp(pStr,"fam")) g_fHideFam = FALSE; + else if(!_stricmp(pStr,"asm")) g_fHideAsm = FALSE; + else if(!_stricmp(pStr,"faa")) g_fHideFAA = FALSE; + else if(!_stricmp(pStr,"foa")) g_fHideFOA = FALSE; + else if(!_stricmp(pStr,"psc")) g_fHidePrivScope = FALSE; + } while(pc); + g_fLimitedVisibility = g_fHidePub || + g_fHidePriv || + g_fHideFam || + g_fHideAsm || + g_fHideFAA || + g_fHideFOA || + g_fHidePrivScope; + } + else if (_stricmp(szOpt, "nob") == 0) + { + g_fShowProgressBar = FALSE; + } + else if (_stricmp(szOpt, "quo") == 0) + { + g_fQuoteAllNames = TRUE; + } + else if (_stricmp(szOpt, "utf") == 0) + { + g_uCodePage = CP_UTF8; + } + else if (_stricmp(szOpt, "uni") == 0) + { + g_uCodePage = 0xFFFFFFFF; + } + else if (_stricmp(szOpt, "rtf") == 0) + { + g_fDumpRTF = TRUE; + g_fDumpHTML = FALSE; + } + else if (_stricmp(szOpt, "htm") == 0) + { + g_fDumpRTF = FALSE; + g_fDumpHTML = TRUE; + } + else if (_stricmp(szOpt, "all") == 0) + { + g_fDumpStats = g_fTDC; + g_fDumpHeader = TRUE; + g_fShowBytes = TRUE; + g_fDumpClassList = g_fTDC; + g_fDumpTokens = TRUE; + } + else if (_stricmp(szOpt, "ite") == 0) + { + char *pStr = EqualOrColon(szArg); + char *p, *q; + if(pStr == NULL) return -1; + pStr++; + pStr = CheckForDQuotes(pStr); + // treat it as meaning "dump only class X" or "class X method Y" + p = strchr(pStr, ':'); + + if (p == NULL) + { + // dump one class + g_Mode = MODE_DUMP_CLASS; + strcpy_s(g_pszClassToDump, MAX_CLASSNAME_LENGTH, pStr); + } + else + { + *p++ = '\0'; + if (*p != ':') return -1; + + strcpy_s(g_pszClassToDump, MAX_CLASSNAME_LENGTH, pStr); + + p++; + + q = strchr(p, '('); + if (q == NULL) + { + // dump class::method + g_Mode = MODE_DUMP_CLASS_METHOD; + strcpy_s(g_pszMethodToDump, MAX_MEMBER_LENGTH, p); + } + else + { + // dump class::method(sig) + g_Mode = MODE_DUMP_CLASS_METHOD_SIG; + *q = '\0'; + strcpy_s(g_pszMethodToDump, MAX_MEMBER_LENGTH, p); + // get rid of external parentheses: + q++; + strcpy_s(g_pszSigToDump, MAX_SIGNATURE_LENGTH, q); + } + } + } + else if ((_stricmp(szOpt, "met") == 0)&&g_fTDC) + { + if(g_fTDC) + { + char *pStr = EqualOrColon(szArg); + g_fDumpMetaInfo = TRUE; + if(pStr) + { + char szOptn[64]; + strncpy_s(szOptn, 64, pStr+1,10); + szOptn[3] = 0; // recognize metainfo specifier by first 3 chars + if (_stricmp(szOptn, "hex") == 0) g_ulMetaInfoFilter |= MDInfo::dumpMoreHex; + else if(_stricmp(szOptn, "csv") == 0) g_ulMetaInfoFilter |= MDInfo::dumpCSV; + else if(_stricmp(szOptn, "mdh") == 0) g_ulMetaInfoFilter |= MDInfo::dumpHeader; + else if(_stricmp(szOptn, "raw") == 0) g_ulMetaInfoFilter |= MDInfo::dumpRaw; + else if(_stricmp(szOptn, "hea") == 0) g_ulMetaInfoFilter |= MDInfo::dumpRawHeaps; + else if(_stricmp(szOptn, "sch") == 0) g_ulMetaInfoFilter |= MDInfo::dumpSchema; + else if(_stricmp(szOptn, "unr") == 0) g_ulMetaInfoFilter |= MDInfo::dumpUnsat; + else if(_stricmp(szOptn, "val") == 0) g_ulMetaInfoFilter |= MDInfo::dumpValidate; + else if(_stricmp(szOptn, "sta") == 0) g_ulMetaInfoFilter |= MDInfo::dumpStats; + else return -1; + } + } + } + else if (_stricmp(szOpt, "obj") == 0) + { + char *pStr = EqualOrColon(szArg); + if(pStr == NULL) return -1; + pStr++; + pStr = CheckForDQuotes(pStr); + *ppszObjFileName = new char[strlen(pStr)+1]; + strcpy_s(*ppszObjFileName,strlen(pStr)+1,pStr); + } + else if (_stricmp(szOpt, "out") == 0) + { + char *pStr = EqualOrColon(szArg); + if(pStr == NULL) return -1; + pStr++; + pStr = CheckForDQuotes(pStr); + if(*pStr == 0) return -1; + if(_stricmp(pStr,"con")) + { + strncpy_s(g_szOutputFile, MAX_FILENAME_LENGTH, pStr,MAX_FILENAME_LENGTH-1); + g_szOutputFile[MAX_FILENAME_LENGTH-1] = 0; + } + else + g_fShowProgressBar = FALSE; + + g_Mode &= ~MODE_GUI; + } + else if (_stricmp(szOpt, "tex") == 0) + { + g_Mode &= ~MODE_GUI; + g_fShowProgressBar = FALSE; + } + else + { + PrintLogo(); + printf(RstrANSI(IDS_E_INVALIDOPTION),szArg); //"INVALID COMMAND LINE OPTION: %s\n\n",szArg); + return -1; + } + } + else + { + if(g_szInputFile[0]) + { + PrintLogo(); + printf(RstrANSI(IDS_E_MULTIPLEINPUT)); //"MULTIPLE INPUT FILES SPECIFIED\n\n"); + return -1; // check if it was already specified + } + szArg = CheckForDQuotes(szArg); + strncpy_s(g_szInputFile, MAX_FILENAME_LENGTH,szArg,MAX_FILENAME_LENGTH-1); + g_szInputFile[MAX_FILENAME_LENGTH-1] = 0; + GetInputFileFullPath(); + } + return 0; +} + +char* UTF8toANSI(__in __nullterminated char* szUTF) +{ + ULONG32 L = (ULONG32) strlen(szUTF)+16; + WCHAR* wzUnicode = new WCHAR[L]; + memset(wzUnicode,0,L*sizeof(WCHAR)); + WszMultiByteToWideChar(CP_UTF8,0,szUTF,-1,wzUnicode,L); + L <<= 2; + char* szANSI = new char[L]; + memset(szANSI,0,L); + WszWideCharToMultiByte(g_uConsoleCP,0,wzUnicode,-1,szANSI,L,NULL,NULL); + VDELETE(wzUnicode); + return szANSI; +} +char* ANSItoUTF8(__in __nullterminated char* szANSI) +{ + ULONG32 L = (ULONG32) strlen(szANSI)+16; + WCHAR* wzUnicode = new WCHAR[L]; + memset(wzUnicode,0,L*sizeof(WCHAR)); + WszMultiByteToWideChar(g_uConsoleCP,0,szANSI,-1,wzUnicode,L); + L *= 3; + char* szUTF = new char[L]; + memset(szUTF,0,L); + WszWideCharToMultiByte(CP_UTF8,0,wzUnicode,-1,szUTF,L,NULL,NULL); + VDELETE(wzUnicode); + return szUTF; +} + +int ParseCmdLineW(__in __nullterminated WCHAR* wzCmdLine, __out char** ppszObjFileName) +{ + int argc,ret=0; + LPWSTR* argv= CommandLineToArgvW(wzCmdLine,&argc); + char* szArg = new char[2048]; + for(int i=1; i < argc; i++) + { + memset(szArg,0,2048); + WszWideCharToMultiByte(CP_UTF8,0,argv[i],-1,szArg,2048,NULL,NULL); + if(ret = ProcessOneArg(szArg,ppszObjFileName)) break; + } + VDELETE(szArg); + return ret; +} + +int ParseCmdLineA(__in __nullterminated char* szCmdLine, __out char** ppszObjFileName) +{ + if((szCmdLine == NULL)||(*szCmdLine == 0)) return 0; + + // ANSI to UTF-8 + char* szCmdLineUTF = ANSItoUTF8(szCmdLine); + + // Split into argv[] + int argc=0, ret = 0; + DynamicArray<char*> argv; + char* pch; + char* pchend; + bool bUnquoted = true; + + pch = szCmdLineUTF; + pchend = pch+strlen(szCmdLineUTF); + while(pch) + { + for(; *pch == ' '; pch++); // skip the blanks + argv[argc++] = pch; + for(; pch < pchend; pch++) + { + if(*pch == '"') bUnquoted = !bUnquoted; + else if((*pch == ' ')&&bUnquoted) break; + } + + if(pch < pchend) *pch++ = 0; + else break; + } + + for(int i=1; i < argc; i++) + { + if(ret = ProcessOneArg(argv[i],ppszObjFileName)) break; + } + VDELETE(szCmdLineUTF); + return ret; +} + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + __in LPSTR lpCmdLine, + int nCmdShow) +{ + // ildasm does not need to be SO-robust. + SO_NOT_MAINLINE_FUNCTION; + + // SWI has requested that the exact form of the function call below be used. For details see http://swi/SWI%20Docs/Detecting%20Heap%20Corruption.doc + (void)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); + +#ifdef _DEBUG + DisableThrowCheck(); +#endif + + int iCommandLineParsed = 0; + WCHAR* wzCommandLine = NULL; + char* szCommandLine = NULL; + + g_fUseProperName = TRUE; + + g_hInstance = hInstance; + g_Mode = MODE_GUI; + g_pszClassToDump[0]=0; + g_pszMethodToDump[0]=0; + g_pszSigToDump[0]=0; + memset(g_szInputFile,0,MAX_FILENAME_LENGTH); + memset(g_szOutputFile,0,MAX_FILENAME_LENGTH); +#if defined(_DEBUG) + g_fTDC = TRUE; +#endif + +#undef GetCommandLineW +#undef CreateProcessW + g_pszObjFileName = NULL; + + g_szAsmCodeIndent[0] = 0; + hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE); + hConsoleErr = GetStdHandle(STD_ERROR_HANDLE); + + // Dev11 #5320 - pull the localized resource loader up so if ParseCmdLineW need resources, they're already loaded + g_hResources = LoadLocalizedResourceDLLForSDK(L"ildasmrc.dll"); + + iCommandLineParsed = ParseCmdLineW((wzCommandLine = GetCommandLineW()),&g_pszObjFileName); + + if(!g_fLimitedVisibility) + { + g_fHidePub = FALSE; + g_fHidePriv = FALSE; + g_fHideFam = FALSE; + g_fHideAsm = FALSE; + g_fHideFAA = FALSE; + g_fHideFOA = FALSE; + g_fHidePrivScope = FALSE; + } + if(hConsoleOut != INVALID_HANDLE_VALUE) //First pass: console + { + g_uConsoleCP = GetConsoleOutputCP(); + + if(iCommandLineParsed) + { + if(iCommandLineParsed > 0) PrintLogo(); + SyntaxCon(); + exit((iCommandLineParsed == 1) ? 0 : 1); + } + if(!(g_Mode & MODE_GUI)) + { + DWORD exitCode = 1; + if(g_szInputFile[0] == 0) + { + SyntaxCon(); + exit(1); + } + g_pFile = NULL; + if(g_szOutputFile[0]) + { + g_pFile = OpenOutput(g_szOutputFile); + if(g_pFile == NULL) + { + char sz[4096]; + sprintf_s(sz,4096,RstrUTF(IDS_E_CANTOPENOUT)/*"Unable to open '%s' for output."*/, g_szOutputFile); + g_uCodePage = CP_ACP; + printError(NULL,sz); + exit(1); + } + } + else // console output -- force the code page to ANSI + { + g_uCodePage = g_uConsoleCP; + g_fDumpRTF = FALSE; + g_fDumpHTML = FALSE; + } + if (Init() == TRUE) + { + exitCode = DumpFile() ? 0 : 1; + Cleanup(); + } + Uninit(); + exit(exitCode); + } + else // if GUI ordered, restart as WinApp + { + PROCESS_INFORMATION pi; + STARTUPINFO si; + memset(&pi, 0, sizeof(PROCESS_INFORMATION) ); + memset(&si, 0, sizeof(STARTUPINFO) ); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.wShowWindow = SW_SHOW; + si.hStdOutput = INVALID_HANDLE_VALUE; + si.hStdInput = INVALID_HANDLE_VALUE; + si.hStdError = INVALID_HANDLE_VALUE; + // Create the child process. + if(CreateProcessW(NULL, + wzCommandLine, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + DETACHED_PROCESS, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + (LPSTARTUPINFOW)&si, // STARTUPINFO pointer + &pi)==0) // receives PROCESS_INFORMATION + { + printf(RstrANSI(IDS_E_CANTCREATEPROC));//"Failed to CreateProcess\n\n"); + exit(1); + } + exit(0); + } + } + else //Second pass: WinApp + { + g_uCodePage = CP_UTF8; + g_Mode = MODE_GUI; + g_fDumpHTML = FALSE; + + if(g_szInputFile[0]) + { + char* pch = strrchr(g_szInputFile,'.'); + if(pch && (!_strcmpi(pch+1,"lib") || !_strcmpi(pch+1,"obj"))) + { + WszMessageBox(NULL, + RstrW(IDS_ONLYPEINGUI),//"ILDASM supports only PE files in graphic mode", + RstrW(IDS_BADFILETYPE),//"Invalid File Type", + MB_OK|MB_ICONERROR|GetDasmMBRTLStyle()); + return 0; + } + } + if (Init() == TRUE) + { + CreateGUI(); + if(g_szInputFile[0]) + { + GUISetModule(g_szInputFile); + DumpFile(); + } + GUIMainLoop(); + Cleanup(); + DestroyGUI(); + } + Uninit(); + return 0 ; + } + return 0; +} + 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> |