From 4960a3e5fbf17620b6b4c164acebd1d34f37a458 Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Fri, 7 Jul 2017 16:25:55 +0300 Subject: [PATCH] Add class for printint types --- src/debug/debugger/CMakeLists.txt | 3 +- src/debug/debugger/main.cpp | 117 +--------- src/debug/debugger/typeprinter.cpp | 442 +++++++++++++++++++++++++++++++++++++ src/debug/debugger/typeprinter.h | 12 + src/debug/debugger/varobj.cpp | 14 ++ 5 files changed, 476 insertions(+), 112 deletions(-) create mode 100644 src/debug/debugger/typeprinter.cpp create mode 100644 src/debug/debugger/typeprinter.h diff --git a/src/debug/debugger/CMakeLists.txt b/src/debug/debugger/CMakeLists.txt index ebdcaa3..5c4d01e 100644 --- a/src/debug/debugger/CMakeLists.txt +++ b/src/debug/debugger/CMakeLists.txt @@ -6,7 +6,8 @@ set(coreclrdbg_SRC tpa.cpp breakpoints.cpp modules.cpp - varobj.cpp) + varobj.cpp + typeprinter.cpp) if(CLR_CMAKE_PLATFORM_ARCH_AMD64) add_definitions(-D_TARGET_AMD64_=1) diff --git a/src/debug/debugger/main.cpp b/src/debug/debugger/main.cpp index 43b48fb..98463f7 100644 --- a/src/debug/debugger/main.cpp +++ b/src/debug/debugger/main.cpp @@ -15,10 +15,6 @@ #include #include -typedef char * LPCUTF8; -typedef uintptr_t TADDR; -#include "sos_md.h" - #include #include "torelease.h" @@ -131,6 +127,9 @@ HRESULT GetFrameLocation(ICorDebugFrame *pFrame, // Varobj HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output); +// TypePrinter +#include "typeprinter.h" + HRESULT PrintThread(ICorDebugThread *pThread, std::string &output) { HRESULT Status = S_OK; @@ -328,46 +327,6 @@ HRESULT RunStep(ICorDebugThread *pThread, StepType stepType) return S_OK; } -static HRESULT NameForTypeDef_s(mdTypeDef tkTypeDef, IMetaDataImport *pImport, - WCHAR *mdName, size_t capacity_mdName) -{ - DWORD flags; - ULONG nameLen; - - HRESULT hr = pImport->GetTypeDefProps(tkTypeDef, mdName, - mdNameLen, &nameLen, - &flags, NULL); - if (hr != S_OK) { - return hr; - } - - if (!IsTdNested(flags)) { - return hr; - } - mdTypeDef tkEnclosingClass; - hr = pImport->GetNestedClassProps(tkTypeDef, &tkEnclosingClass); - if (hr != S_OK) { - return hr; - } - WCHAR *name = (WCHAR*)_alloca((nameLen+1)*sizeof(WCHAR)); - wcscpy_s (name, nameLen+1, mdName); - hr = NameForTypeDef_s(tkEnclosingClass,pImport,mdName, capacity_mdName); - if (hr != S_OK) { - return hr; - } - size_t Len = _wcslen (mdName); - if (Len < mdNameLen-2) { - mdName[Len++] = L'+'; - mdName[Len] = L'\0'; - } - Len = mdNameLen-1 - Len; - if (Len > nameLen) { - Len = nameLen; - } - wcsncat_s (mdName,capacity_mdName,name,Len); - return hr; -} - HRESULT PrintFrames(ICorDebugThread *pThread, std::string &output) { HRESULT Status; @@ -437,74 +396,10 @@ HRESULT PrintFrames(ICorDebugThread *pThread, std::string &output) if (!frameLocation.empty()) ss << frameLocation << ","; - ToRelease pClass; - ToRelease pModule; - mdMethodDef methodDef; - IfFailRet(pFunction->GetClass(&pClass)); - IfFailRet(pFunction->GetModule(&pModule)); - IfFailRet(pFunction->GetToken(&methodDef)); - - WCHAR wszModuleName[100]; - ULONG32 cchModuleNameActual; - IfFailRet(pModule->GetName(_countof(wszModuleName), &cchModuleNameActual, wszModuleName)); - - ToRelease pMDUnknown; - ToRelease pMD; - - IfFailRet(pModule->GetMetaDataInterface(IID_IMetaDataImport, &pMDUnknown)); - IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport, (LPVOID*) &pMD)); - - mdTypeDef typeDef; - IfFailRet(pClass->GetToken(&typeDef)); - - HRESULT hr; - mdTypeDef memTypeDef; - ULONG nameLen; - DWORD flags; - PCCOR_SIGNATURE pbSigBlob; - ULONG ulSigBlob; - ULONG ulCodeRVA; - ULONG ulImplFlags; - - WCHAR szFunctionName[1024] = {0}; - - hr = pMD->GetMethodProps(methodDef, &memTypeDef, - szFunctionName, _countof(szFunctionName), &nameLen, - &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags); - szFunctionName[nameLen] = L'\0'; - WCHAR m_szName[mdNameLen] = {0}; - m_szName[0] = L'\0'; - - if (memTypeDef != mdTypeDefNil) - { - hr = NameForTypeDef_s (memTypeDef, pMD, m_szName, _countof(m_szName)); - if (SUCCEEDED (hr)) { - wcscat_s (m_szName, _countof(m_szName), W(".")); - } - } - wcscat_s (m_szName, _countof(m_szName), szFunctionName); - - ToRelease pIMDI; - IfFailRet(GetMDInternalFromImport(pMD, &pIMDI)); - - LPCSTR szName = NULL; - LPCSTR szNameSpace = NULL; - pIMDI->GetNameOfTypeDef(memTypeDef, &szName, &szNameSpace); - - // CORDB_ADDRESS modAddress; - // IfFailRet(pModule->GetBaseAddress(&modAddress)); - // WCHAR cBuffer[2048]; - // PrettyPrintClassFromToken(modAddress, typeDef, cBuffer, 2048); - // IMDInternalImport *pIMDI; - - // TODO: - // LONG lSigBlobRemaining; - // hr = GetFullNameForMD(pbSigBlob, ulSigBlob, &lSigBlobRemaining); - - char funcName[2048] = {0}; - WideCharToMultiByte(CP_UTF8, 0, m_szName, (int)(_wcslen(m_szName) + 1), funcName, _countof(funcName), NULL, NULL); + std::string funcType; + TypePrinter::GetMethodType(pFunction, funcType); - ss << "func=\"" << szName << "." << szName << "\"}"; + ss << "func=\"" << funcType << "\"}"; } ss << "]"; diff --git a/src/debug/debugger/typeprinter.cpp b/src/debug/debugger/typeprinter.cpp new file mode 100644 index 0000000..fc6fe43 --- /dev/null +++ b/src/debug/debugger/typeprinter.cpp @@ -0,0 +1,442 @@ +#include + +#include "corhdr.h" +#include "cor.h" +#include "cordebug.h" +#include "debugshim.h" + +#include +#include +#include +#include +#include +#include + +#include "torelease.h" +#include "arrayholder.h" + +typedef char * LPCUTF8; +typedef uintptr_t TADDR; +#include "sos_md.h" + +#include "typeprinter.h" + +// Get rid of these! Don't use them any more! +#define MAX_CLASSNAME_LENGTH 1024 +#define MAX_NAMESPACE_LENGTH 1024 + + +// From metadata.cpp + +/**********************************************************************\ +* Routine Description: * +* * +* This function is called to find the name of a TypeDef using * +* metadata API. * +* * +\**********************************************************************/ +// Caller should guard against exception +// !!! mdName should have at least mdNameLen WCHAR +HRESULT TypePrinter::NameForTypeDef_s(mdTypeDef tkTypeDef, IMetaDataImport *pImport, + WCHAR *mdName, size_t capacity_mdName) +{ + DWORD flags; + ULONG nameLen; + + HRESULT hr = pImport->GetTypeDefProps(tkTypeDef, mdName, + mdNameLen, &nameLen, + &flags, NULL); + if (hr != S_OK) { + return hr; + } + + if (!IsTdNested(flags)) { + return hr; + } + mdTypeDef tkEnclosingClass; + hr = pImport->GetNestedClassProps(tkTypeDef, &tkEnclosingClass); + if (hr != S_OK) { + return hr; + } + WCHAR *name = (WCHAR*)_alloca((nameLen+1)*sizeof(WCHAR)); + wcscpy_s (name, nameLen+1, mdName); + hr = NameForTypeDef_s(tkEnclosingClass,pImport,mdName, capacity_mdName); + if (hr != S_OK) { + return hr; + } + size_t Len = _wcslen (mdName); + if (Len < mdNameLen-2) { + mdName[Len++] = L'+'; + mdName[Len] = L'\0'; + } + Len = mdNameLen-1 - Len; + if (Len > nameLen) { + Len = nameLen; + } + wcsncat_s (mdName,capacity_mdName,name,Len); + return hr; +} + +HRESULT TypePrinter::NameForToken_s(mdTypeDef mb, IMetaDataImport *pImport, WCHAR *mdName, size_t capacity_mdName, + bool bClassName) +{ + mdName[0] = L'\0'; + if ((mb & 0xff000000) != mdtTypeDef + && (mb & 0xff000000) != mdtFieldDef + && (mb & 0xff000000) != mdtMethodDef) + { + //ExtOut("unsupported\n"); + return E_FAIL; + } + + HRESULT hr = E_FAIL; + + PAL_CPP_TRY + { + WCHAR name[MAX_CLASSNAME_LENGTH]; + if ((mb & 0xff000000) == mdtTypeDef) + { + hr = NameForTypeDef_s (mb, pImport, mdName, capacity_mdName); + } + else if ((mb & 0xff000000) == mdtFieldDef) + { + mdTypeDef mdClass; + ULONG size; + hr = pImport->GetMemberProps(mb, &mdClass, + name, sizeof(name)/sizeof(WCHAR)-1, &size, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); + if (SUCCEEDED(hr)) + { + if (mdClass != mdTypeDefNil && bClassName) + { + hr = NameForTypeDef_s (mdClass, pImport, mdName, capacity_mdName); + wcscat_s (mdName, capacity_mdName, W(".")); + } + name[size] = L'\0'; + wcscat_s (mdName, capacity_mdName, name); + } + } + else if ((mb & 0xff000000) == mdtMethodDef) + { + mdTypeDef mdClass; + ULONG size; + hr = pImport->GetMethodProps(mb, &mdClass, + name, sizeof(name)/sizeof(WCHAR)-1, &size, + NULL, NULL, NULL, NULL, NULL); + if (SUCCEEDED (hr)) + { + if (mdClass != mdTypeDefNil && bClassName) + { + hr = NameForTypeDef_s (mdClass, pImport, mdName, capacity_mdName); + wcscat_s (mdName, capacity_mdName, W(".")); + } + name[size] = L'\0'; + wcscat_s (mdName, capacity_mdName, name); + } + } + else + { + //ExtOut ("Unsupported token type\n"); + hr = E_FAIL; + } + } + PAL_CPP_CATCH_ALL + { + hr = E_FAIL; + } + PAL_CPP_ENDTRY + return hr; +} + +// From strike.cpp + +HRESULT TypePrinter::AddGenericArgs(ICorDebugType *pType, std::stringstream &ss) +{ + ToRelease pTypeEnum; + + if (SUCCEEDED(pType->EnumerateTypeParameters(&pTypeEnum))) + { + ULONG numTypes = 0; + ToRelease pCurrentTypeParam; + + bool isFirst = true; + + while (SUCCEEDED(pTypeEnum->Next(1, &pCurrentTypeParam, &numTypes)) && numTypes == 1) + { + ss << (isFirst ? "<" : ","); + isFirst = false; + + std::string name; + GetTypeOfValue(pCurrentTypeParam, name); + ss << name; + } + if(!isFirst) + ss << ">"; + } + + return S_OK; +} + +HRESULT TypePrinter::GetTypeOfValue(ICorDebugValue *pValue, std::string &output) +{ + HRESULT Status = S_OK; + + CorElementType corElemType; + IfFailRet(pValue->GetType(&corElemType)); + + ToRelease pType; + ToRelease pValue2; + if(SUCCEEDED(pValue->QueryInterface(IID_ICorDebugValue2, (void**) &pValue2)) && SUCCEEDED(pValue2->GetExactType(&pType))) + return GetTypeOfValue(pType, output); + else + output = ""; + + return S_OK; +} + +HRESULT TypePrinter::GetTypeOfValue(ICorDebugType *pType, std::string &output) +{ + std::stringstream ss; + + HRESULT Status = S_OK; + + CorElementType corElemType; + IfFailRet(pType->GetType(&corElemType)); + + switch (corElemType) + { + //List of unsupported CorElementTypes: + //ELEMENT_TYPE_END = 0x0, + //ELEMENT_TYPE_VAR = 0x13, // a class type variable VAR + //ELEMENT_TYPE_GENERICINST = 0x15, // GENERICINST ... + //ELEMENT_TYPE_TYPEDBYREF = 0x16, // TYPEDREF (it takes no args) a typed referece to some other type + //ELEMENT_TYPE_MVAR = 0x1e, // a method type variable MVAR + //ELEMENT_TYPE_CMOD_REQD = 0x1F, // required C modifier : E_T_CMOD_REQD + //ELEMENT_TYPE_CMOD_OPT = 0x20, // optional C modifier : E_T_CMOD_OPT + //ELEMENT_TYPE_INTERNAL = 0x21, // INTERNAL + //ELEMENT_TYPE_MAX = 0x22, // first invalid element type + //ELEMENT_TYPE_MODIFIER = 0x40, + //ELEMENT_TYPE_SENTINEL = 0x01 | ELEMENT_TYPE_MODIFIER, // sentinel for varargs + //ELEMENT_TYPE_PINNED = 0x05 | ELEMENT_TYPE_MODIFIER, + //ELEMENT_TYPE_R4_HFA = 0x06 | ELEMENT_TYPE_MODIFIER, // used only internally for R4 HFA types + //ELEMENT_TYPE_R8_HFA = 0x07 | ELEMENT_TYPE_MODIFIER, // used only internally for R8 HFA types + default: + ss << "(Unhandled CorElementType: 0x" << std::hex << corElemType << ")"; + output = ss.str(); + break; + + case ELEMENT_TYPE_VALUETYPE: + case ELEMENT_TYPE_CLASS: + { + //Defaults in case we fail... + output = (corElemType == ELEMENT_TYPE_VALUETYPE) ? "struct" : "class"; + + mdTypeDef typeDef; + ToRelease pClass; + if(SUCCEEDED(pType->GetClass(&pClass)) && SUCCEEDED(pClass->GetToken(&typeDef))) + { + ToRelease pModule; + IfFailRet(pClass->GetModule(&pModule)); + + ToRelease pMDUnknown; + ToRelease pMD; + IfFailRet(pModule->GetMetaDataInterface(IID_IMetaDataImport, &pMDUnknown)); + IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport, (LPVOID*) &pMD)); + + WCHAR g_mdName[mdNameLen]; + + if(SUCCEEDED(NameForToken_s(TokenFromRid(typeDef, mdtTypeDef), pMD, g_mdName, mdNameLen, false))) + { + char cName[mdNameLen] = {0}; + WideCharToMultiByte(CP_UTF8, 0, g_mdName, (int)(_wcslen(g_mdName) + 1), cName, _countof(cName), NULL, NULL); + ss << cName; + } + + } + AddGenericArgs(pType, ss); + output = ss.str(); + return S_OK; + } + break; + case ELEMENT_TYPE_VOID: + output = "void"; + break; + case ELEMENT_TYPE_BOOLEAN: + output = "bool"; + break; + case ELEMENT_TYPE_CHAR: + output = "char"; + break; + case ELEMENT_TYPE_I1: + output = "sbyte"; + break; + case ELEMENT_TYPE_U1: + output = "byte"; + break; + case ELEMENT_TYPE_I2: + output = "short"; + break; + case ELEMENT_TYPE_U2: + output = "ushort"; + break; + case ELEMENT_TYPE_I4: + output = "int"; + break; + case ELEMENT_TYPE_U4: + output = "uint"; + break; + case ELEMENT_TYPE_I8: + output = "long"; + break; + case ELEMENT_TYPE_U8: + output = "ulong"; + break; + case ELEMENT_TYPE_R4: + output = "float"; + break; + case ELEMENT_TYPE_R8: + output = "double"; + break; + case ELEMENT_TYPE_OBJECT: + output = "object"; + break; + case ELEMENT_TYPE_STRING: + output = "string"; + break; + case ELEMENT_TYPE_I: + output = "IntPtr"; + break; + case ELEMENT_TYPE_U: + output = "UIntPtr"; + break; + case ELEMENT_TYPE_SZARRAY: + case ELEMENT_TYPE_ARRAY: + case ELEMENT_TYPE_BYREF: + case ELEMENT_TYPE_PTR: + { + std::string elementTypeName; + ToRelease pFirstParameter; + if(SUCCEEDED(pType->GetFirstTypeParameter(&pFirstParameter))) + GetTypeOfValue(pFirstParameter, elementTypeName); + else + elementTypeName = ""; + + ss << elementTypeName; + + switch(corElemType) + { + case ELEMENT_TYPE_SZARRAY: + ss << "[]"; + output = ss.str(); + return S_OK; + case ELEMENT_TYPE_ARRAY: + { + ULONG32 rank = 0; + pType->GetRank(&rank); + ss << "["; + for(ULONG32 i = 0; i < rank - 1; i++) + ss << ","; + ss << "]"; + output = ss.str(); + } + return S_OK; + case ELEMENT_TYPE_BYREF: + ss << "&"; + output = ss.str(); + return S_OK; + case ELEMENT_TYPE_PTR: + ss << "*"; + output = ss.str(); + return S_OK; + default: + // note we can never reach here as this is a nested switch + // and corElemType can only be one of the values above + break; + } + } + break; + case ELEMENT_TYPE_FNPTR: + output = "*(...)"; + break; + case ELEMENT_TYPE_TYPEDBYREF: + output = "typedbyref"; + break; + } + return S_OK; +} + +HRESULT TypePrinter::GetMethodType(ICorDebugFunction *pFunction, std::string &output) +{ + HRESULT Status; + + ToRelease pClass; + ToRelease pModule; + mdMethodDef methodDef; + IfFailRet(pFunction->GetClass(&pClass)); + IfFailRet(pFunction->GetModule(&pModule)); + IfFailRet(pFunction->GetToken(&methodDef)); + + WCHAR wszModuleName[100]; + ULONG32 cchModuleNameActual; + IfFailRet(pModule->GetName(_countof(wszModuleName), &cchModuleNameActual, wszModuleName)); + + ToRelease pMDUnknown; + ToRelease pMD; + + IfFailRet(pModule->GetMetaDataInterface(IID_IMetaDataImport, &pMDUnknown)); + IfFailRet(pMDUnknown->QueryInterface(IID_IMetaDataImport, (LPVOID*) &pMD)); + + mdTypeDef typeDef; + IfFailRet(pClass->GetToken(&typeDef)); + + HRESULT hr; + mdTypeDef memTypeDef; + ULONG nameLen; + DWORD flags; + PCCOR_SIGNATURE pbSigBlob; + ULONG ulSigBlob; + ULONG ulCodeRVA; + ULONG ulImplFlags; + + WCHAR szFunctionName[1024] = {0}; + + hr = pMD->GetMethodProps(methodDef, &memTypeDef, + szFunctionName, _countof(szFunctionName), &nameLen, + &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags); + szFunctionName[nameLen] = L'\0'; + WCHAR m_szName[mdNameLen] = {0}; + m_szName[0] = L'\0'; + + if (memTypeDef != mdTypeDefNil) + { + hr = NameForTypeDef_s (memTypeDef, pMD, m_szName, _countof(m_szName)); + if (SUCCEEDED (hr)) { + wcscat_s (m_szName, _countof(m_szName), W(".")); + } + } + wcscat_s (m_szName, _countof(m_szName), szFunctionName); + + ToRelease pIMDI; + IfFailRet(GetMDInternalFromImport(pMD, &pIMDI)); + + LPCSTR szName = NULL; + LPCSTR szNameSpace = NULL; + pIMDI->GetNameOfTypeDef(memTypeDef, &szName, &szNameSpace); + + // CORDB_ADDRESS modAddress; + // IfFailRet(pModule->GetBaseAddress(&modAddress)); + // WCHAR cBuffer[2048]; + // PrettyPrintClassFromToken(modAddress, typeDef, cBuffer, 2048); + // IMDInternalImport *pIMDI; + + // TODO: + // LONG lSigBlobRemaining; + // hr = GetFullNameForMD(pbSigBlob, ulSigBlob, &lSigBlobRemaining); + + char funcName[2048] = {0}; + WideCharToMultiByte(CP_UTF8, 0, m_szName, (int)(_wcslen(m_szName) + 1), funcName, _countof(funcName), NULL, NULL); + + output = funcName; + return S_OK; +} diff --git a/src/debug/debugger/typeprinter.h b/src/debug/debugger/typeprinter.h new file mode 100644 index 0000000..fff7103 --- /dev/null +++ b/src/debug/debugger/typeprinter.h @@ -0,0 +1,12 @@ +class TypePrinter +{ + static HRESULT NameForTypeDef_s(mdTypeDef tkTypeDef, IMetaDataImport *pImport, + WCHAR *mdName, size_t capacity_mdName); + static HRESULT NameForToken_s(mdTypeDef mb, IMetaDataImport *pImport, WCHAR *mdName, size_t capacity_mdName, + bool bClassName); + static HRESULT AddGenericArgs(ICorDebugType *pType, std::stringstream &ss); +public: + static HRESULT GetTypeOfValue(ICorDebugType *pType, std::string &output); + static HRESULT GetTypeOfValue(ICorDebugValue *pValue, std::string &output); + static HRESULT GetMethodType(ICorDebugFunction *pFunction, std::string &output); +}; diff --git a/src/debug/debugger/varobj.cpp b/src/debug/debugger/varobj.cpp index ce3956c..b13d0da 100644 --- a/src/debug/debugger/varobj.cpp +++ b/src/debug/debugger/varobj.cpp @@ -24,6 +24,7 @@ HRESULT GetFrameNamedLocalVariable( std::string ¶mName, ICorDebugValue** ppValue); +#include "typeprinter.h" // From strike.cpp static HRESULT DereferenceAndUnboxValue(ICorDebugValue * pValue, ICorDebugValue** ppOutputValue, BOOL * pIsNull = NULL) @@ -272,6 +273,7 @@ HRESULT PrintValue(ICorDebugValue *pInputValue, ICorDebugILFrame * pILFrame, IMe HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output) { bool printValues = true; + bool printTypes = true; HRESULT Status; ToRelease pILFrame; @@ -345,6 +347,12 @@ HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output) if (SUCCEEDED(PrintValue(pValue, pILFrame, pMD, strVal))) ss << ",value=\"" << strVal << "\""; } + if (printTypes) + { + std::string strVal; + if (SUCCEEDED(TypePrinter::GetTypeOfValue(pValue, strVal))) + ss << ",type=\"" << strVal << "\""; + } ss << "}"; sep = ","; } @@ -377,6 +385,12 @@ HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output) if (SUCCEEDED(PrintValue(pValue, pILFrame, pMD, strVal))) ss << ",value=\"" << strVal << "\""; } + if (printTypes) + { + std::string strVal; + if (SUCCEEDED(TypePrinter::GetTypeOfValue(pValue, strVal))) + ss << ",type=\"" << strVal << "\""; + } ss << "}"; sep = ","; } -- 2.7.4