From 4a7ee67a60fb2c40d755dfd4f7e2824954650193 Mon Sep 17 00:00:00 2001 From: David Mason Date: Thu, 7 Sep 2017 15:56:30 -0700 Subject: [PATCH] Make dumpmd work with tiered jitting. Now displays previous code addresses (#13805) * Make dumpmd work with tiered jitting. Now displays previous code addresses * add tier info and nativecodeversionnode ptr to dumpmd output * fix warnings on non-rejit platforms --- src/ToolBox/SOS/Strike/util.cpp | 87 ++++++++++++++--- src/debug/daccess/daccess.cpp | 4 + src/debug/daccess/dacimpl.h | 6 +- src/debug/daccess/request.cpp | 185 +++++++++++++++++++++++++++++-------- src/inc/dacprivate.h | 19 +++- src/inc/sospriv.idl | 12 ++- src/pal/prebuilt/idl/sospriv_i.cpp | 3 + src/pal/prebuilt/inc/sospriv.h | 86 +++++++++++++++++ src/vm/codeversion.h | 4 +- 9 files changed, 348 insertions(+), 58 deletions(-) diff --git a/src/ToolBox/SOS/Strike/util.cpp b/src/ToolBox/SOS/Strike/util.cpp index 3cdebcf..c5dfef2 100644 --- a/src/ToolBox/SOS/Strike/util.cpp +++ b/src/ToolBox/SOS/Strike/util.cpp @@ -88,8 +88,8 @@ ICorDebugProcess *g_pCorDebugProcess = NULL; #endif // IfFailGo // Max number of reverted rejit versions that !dumpmd and !ip2md will print -const UINT kcMaxRevertedRejitData = 10; - +const UINT kcMaxRevertedRejitData = 10; +const UINT kcMaxTieredVersions = 10; #ifndef FEATURE_PAL // ensure we always allocate on the process heap @@ -3252,10 +3252,53 @@ const char *EHTypeName(EHClauseType et) return "UNKNOWN"; } -void DumpRejitData(DacpReJitData * pReJitData) +void DumpTieredNativeCodeAddressInfo(struct DacpTieredVersionData * pTieredVersionData, const UINT cTieredVersionData) +{ + ExtOut("Code Version History:\n"); + + for(int i = cTieredVersionData - 1; i >= 0; --i) + { + const char *descriptor = NULL; + switch(pTieredVersionData[i].TieredInfo) + { + case DacpTieredVersionData::TIERED_UNKNOWN: + default: + _ASSERTE(!"Update SOS to understand the new tier"); + descriptor = "Unknown Tier"; + break; + case DacpTieredVersionData::NON_TIERED: + descriptor = "Non-Tiered"; + break; + case DacpTieredVersionData::TIERED_0: + descriptor = "Tier 0"; + break; + case DacpTieredVersionData::TIERED_1: + descriptor = "Tier 1"; + break; + } + + DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor); + ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr)); + } +} + +void DumpRejitData(CLRDATA_ADDRESS pMethodDesc, DacpReJitData * pReJitData) { ExtOut(" ReJITID %p: ", SOS_PTR(pReJitData->rejitID)); - DMLOut("CodeAddr = %s", DMLIP(pReJitData->NativeCodeAddr)); + + struct DacpTieredVersionData codeAddrs[kcMaxTieredVersions]; + int cCodeAddrs; + + ReleaseHolder sos5; + if (SUCCEEDED(g_sos->QueryInterface(__uuidof(ISOSDacInterface5), &sos5)) && + SUCCEEDED(sos5->GetTieredVersions(pMethodDesc, + (int)pReJitData->rejitID, + codeAddrs, + kcMaxTieredVersions, + &cCodeAddrs))) + { + DumpTieredNativeCodeAddressInfo(codeAddrs, cCodeAddrs); + } LPCSTR szFlags; switch (pReJitData->flags) @@ -3277,6 +3320,7 @@ void DumpRejitData(DacpReJitData * pReJitData) szFlags = " (reverted)"; break; } + ExtOut("%s\n", szFlags); } @@ -3314,18 +3358,18 @@ void DumpAllRejitDataIfNecessary(DacpMethodDescData * pMethodDescData, DacpReJit ExtOut("ReJITed versions:\n"); // Dump CURRENT rejit info - DumpRejitData(&pMethodDescData->rejitDataCurrent); + DumpRejitData(pMethodDescData->MethodDescPtr, &pMethodDescData->rejitDataCurrent); // Dump reverted rejit infos for (ULONG i=0; i < cRevertedRejitData; i++) { - DumpRejitData(&pRevertedRejitData[i]); + DumpRejitData(pMethodDescData->MethodDescPtr, &pRevertedRejitData[i]); } // For !ip2md, ensure we dump the rejit version corresponding to the specified IP // (if not already dumped) if (ShouldDumpRejitDataRequested(pMethodDescData, pRevertedRejitData, cRevertedRejitData)) - DumpRejitData(&pMethodDescData->rejitDataRequested); + DumpRejitData(pMethodDescData->MethodDescPtr, &pMethodDescData->rejitDataRequested); // If we maxed out the reverted versions we dumped, let user know there may be more if (cRevertedRejitData == kcMaxRevertedRejitData) @@ -3344,20 +3388,35 @@ void DumpMDInfoFromMethodDescData(DacpMethodDescData * pMethodDescData, DacpReJi if (!fStackTraceFormat) { - ExtOut("Method Name: %S\n", wszNameBuffer); + ExtOut("Method Name: %S\n", wszNameBuffer); DacpMethodTableData mtdata; if (SUCCEEDED(mtdata.Request(g_sos, pMethodDescData->MethodTablePtr))) { - DMLOut("Class: %s\n", DMLClass(mtdata.Class)); + DMLOut("Class: %s\n", DMLClass(mtdata.Class)); } - DMLOut("MethodTable: %s\n", DMLMethodTable(pMethodDescData->MethodTablePtr)); - ExtOut("mdToken: %p\n", SOS_PTR(pMethodDescData->MDToken)); - DMLOut("Module: %s\n", DMLModule(pMethodDescData->ModulePtr)); - ExtOut("IsJitted: %s\n", pMethodDescData->bHasNativeCode ? "yes" : "no"); - DMLOut("CodeAddr: %s\n", DMLIP(pMethodDescData->NativeCodeAddr)); + DMLOut("MethodTable: %s\n", DMLMethodTable(pMethodDescData->MethodTablePtr)); + ExtOut("mdToken: %p\n", SOS_PTR(pMethodDescData->MDToken)); + DMLOut("Module: %s\n", DMLModule(pMethodDescData->ModulePtr)); + ExtOut("IsJitted: %s\n", pMethodDescData->bHasNativeCode ? "yes" : "no"); + + DMLOut("Current CodeAddr: %s\n", DMLIP(pMethodDescData->NativeCodeAddr)); + + struct DacpTieredVersionData codeAddrs[kcMaxTieredVersions]; + int cCodeAddrs; + ReleaseHolder sos5; + if (SUCCEEDED(g_sos->QueryInterface(__uuidof(ISOSDacInterface5), &sos5)) && + SUCCEEDED(sos5->GetTieredVersions(pMethodDescData->MethodDescPtr, + (int)pMethodDescData->rejitDataCurrent.rejitID, + codeAddrs, + kcMaxTieredVersions, + &cCodeAddrs))) + { + DumpTieredNativeCodeAddressInfo(codeAddrs, cCodeAddrs); + } + DacpMethodDescTransparencyData transparency; if (SUCCEEDED(transparency.Request(g_sos, pMethodDescData->MethodDescPtr))) { diff --git a/src/debug/daccess/daccess.cpp b/src/debug/daccess/daccess.cpp index 9d371ce..12825e0 100644 --- a/src/debug/daccess/daccess.cpp +++ b/src/debug/daccess/daccess.cpp @@ -3275,6 +3275,10 @@ ClrDataAccess::QueryInterface(THIS_ { ifaceRet = static_cast(this); } + else if (IsEqualIID(interfaceId, __uuidof(ISOSDacInterface5))) + { + ifaceRet = static_cast(this); + } else { *iface = NULL; diff --git a/src/debug/daccess/dacimpl.h b/src/debug/daccess/dacimpl.h index b858230..2647c8d 100644 --- a/src/debug/daccess/dacimpl.h +++ b/src/debug/daccess/dacimpl.h @@ -861,7 +861,8 @@ class ClrDataAccess public ISOSDacInterface, public ISOSDacInterface2, public ISOSDacInterface3, - public ISOSDacInterface4 + public ISOSDacInterface4, + public ISOSDacInterface5 { public: ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget=0); @@ -1204,6 +1205,9 @@ public: // ISOSDacInterface4 virtual HRESULT STDMETHODCALLTYPE GetClrNotification(CLRDATA_ADDRESS arguments[], int count, int *pNeeded); + // ISOSDacInterface5 + virtual HRESULT STDMETHODCALLTYPE GetTieredVersions(CLRDATA_ADDRESS methodDesc, int rejitId, struct DacpTieredVersionData *nativeCodeAddrs, int cNativeCodeAddrs, int *pcNativeCodeAddrs); + // // ClrDataAccess. // diff --git a/src/debug/daccess/request.cpp b/src/debug/daccess/request.cpp index a6ab6ea..08136f3 100644 --- a/src/debug/daccess/request.cpp +++ b/src/debug/daccess/request.cpp @@ -845,8 +845,6 @@ void CopyNativeCodeVersionToReJitData(NativeCodeVersion nativeCodeVersion, Nativ } #endif // FEATURE_REJIT - - //--------------------------------------------------------------------------------------- // // Given a method desc addr, this loads up DacpMethodDescData and multiple DacpReJitDatas @@ -872,10 +870,10 @@ void CopyNativeCodeVersionToReJitData(NativeCodeVersion nativeCodeVersion, Nativ // HRESULT ClrDataAccess::GetMethodDescData( - CLRDATA_ADDRESS methodDesc, - CLRDATA_ADDRESS ip, - struct DacpMethodDescData *methodDescData, - ULONG cRevertedRejitVersions, + CLRDATA_ADDRESS methodDesc, + CLRDATA_ADDRESS ip, + struct DacpMethodDescData *methodDescData, + ULONG cRevertedRejitVersions, DacpReJitData * rgRevertedRejitData, ULONG * pcNeededRevertedRejitData) { @@ -904,12 +902,12 @@ HRESULT ClrDataAccess::GetMethodDescData( } else { - ZeroMemory(methodDescData,sizeof(DacpMethodDescData)); + ZeroMemory(methodDescData, sizeof(DacpMethodDescData)); if (rgRevertedRejitData != NULL) - ZeroMemory(rgRevertedRejitData, sizeof(*rgRevertedRejitData)*cRevertedRejitVersions); + ZeroMemory(rgRevertedRejitData, sizeof(*rgRevertedRejitData) * cRevertedRejitVersions); if (pcNeededRevertedRejitData != NULL) *pcNeededRevertedRejitData = 0; - + methodDescData->requestedIP = ip; methodDescData->bHasNativeCode = pMD->HasNativeCode(); methodDescData->bIsDynamic = (pMD->IsLCGMethod()) ? TRUE : FALSE; @@ -925,8 +923,7 @@ HRESULT ClrDataAccess::GetMethodDescData( { methodDescData->NativeCodeAddr = (CLRDATA_ADDRESS)-1; } - methodDescData->AddressOfNativeCodeSlot = pMD->HasNativeCodeSlot() ? - TO_CDADDR(pMD->GetAddrOfNativeCodeSlot()) : NULL; + methodDescData->AddressOfNativeCodeSlot = pMD->HasNativeCodeSlot() ? TO_CDADDR(pMD->GetAddrOfNativeCodeSlot()) : NULL; methodDescData->MDToken = pMD->GetMemberDef(); methodDescData->MethodDescPtr = methodDesc; methodDescData->MethodTablePtr = HOST_CDADDR(pMD->GetMethodTable()); @@ -939,26 +936,24 @@ HRESULT ClrDataAccess::GetMethodDescData( // * ReJitInfo for the requested IP (for !ip2md and !u) // * ReJitInfos for all reverted versions of the method (up to // cRevertedRejitVersions) - // + // // Minidumps will not have all this rejit info, and failure to get rejit info // should not be fatal. So enclose all rejit stuff in a try. EX_TRY { - CodeVersionManager * pCodeVersionManager = pMD->GetCodeVersionManager(); + CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager(); // Current ReJitInfo ILCodeVersion activeILCodeVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD); NativeCodeVersion activeChild = activeILCodeVersion.GetActiveNativeCodeVersion(pMD); - NativeCodeVersionCollection nativeCodeVersions = activeILCodeVersion.GetNativeCodeVersions(pMD); - for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++) + CopyNativeCodeVersionToReJitData(activeChild, activeChild, &methodDescData->rejitDataCurrent); + + if (!activeChild.IsNull()) { - // This arbitrarily captures the first jitted version for the active IL version, but with - // tiered compilation there could be many such method bodies. Before tiered compilation is enabled in a broader set - // of scenarios we need to consider how this change goes all the way up to the UI - probably exposing the - // entire set of methods. - CopyNativeCodeVersionToReJitData(*iter, activeChild, &methodDescData->rejitDataCurrent); - break; + // This was already set previously, but MethodDesc::GetNativeCode is potentially not aware of + // a new native code version, so this is more accurate. + methodDescData->NativeCodeAddr = activeChild.GetNativeCode(); } // Requested ReJitInfo @@ -966,7 +961,7 @@ HRESULT ClrDataAccess::GetMethodDescData( if (methodDescData->requestedIP != NULL) { NativeCodeVersion nativeCodeVersionRequested = pCodeVersionManager->GetNativeCodeVersion( - pMD, + pMD, CLRDATA_ADDRESS_TO_TADDR(methodDescData->requestedIP)); if (!nativeCodeVersionRequested.IsNull()) @@ -1001,7 +996,7 @@ HRESULT ClrDataAccess::GetMethodDescData( // Prepare array to populate with rejitids. "+ 1" because GetReJITIDs // returns all available rejitids, including the rejitid for the one non-reverted // current version. - ReJITID * rgReJitIds = reJitIds.OpenRawBuffer(cRevertedRejitVersions + 1); + ReJITID *rgReJitIds = reJitIds.OpenRawBuffer(cRevertedRejitVersions + 1); if (rgReJitIds != NULL) { hr = ReJitManager::GetReJITIDs(pMD, cRevertedRejitVersions + 1, &cReJitIds, rgReJitIds); @@ -1011,28 +1006,20 @@ HRESULT ClrDataAccess::GetMethodDescData( reJitIds.CloseRawBuffer(cReJitIds); ULONG iRejitDataReverted = 0; ILCodeVersion activeVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD); - for (COUNT_T i=0; - (i < cReJitIds) && (iRejitDataReverted < cRevertedRejitVersions); - i++) + for (COUNT_T i = 0; + (i < cReJitIds) && (iRejitDataReverted < cRevertedRejitVersions); + i++) { ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitIds[i]); - if ((ilCodeVersion.IsNull()) || + if ((ilCodeVersion.IsNull()) || (ilCodeVersion == activeVersion)) { continue; } - NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD); - for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++) - { - // This arbitrarily captures the first jitted version for this reverted IL version, but with - // tiered compilation there could be many such method bodies. Before tiered compilation is enabled in a broader set - // of scenarios we need to consider how this change goes all the way up to the UI - probably exposing the - // entire set of methods. - CopyNativeCodeVersionToReJitData(*iter, activeChild, &rgRevertedRejitData[iRejitDataReverted]); - break; - } + NativeCodeVersion activeRejitChild = ilCodeVersion.GetActiveNativeCodeVersion(pMD); + CopyNativeCodeVersionToReJitData(activeRejitChild, activeChild, &rgRevertedRejitData[iRejitDataReverted]); iRejitDataReverted++; } // pcNeededRevertedRejitData != NULL as per condition at top of function (cuz rgRevertedRejitData != @@ -1048,7 +1035,7 @@ HRESULT ClrDataAccess::GetMethodDescData( *pcNeededRevertedRejitData = 0; } EX_END_CATCH(SwallowAllExceptions) - hr = S_OK; // Failure to get rejitids is not fatal + hr = S_OK; // Failure to get rejitids is not fatal #endif // FEATURE_REJIT #if defined(HAVE_GCCOVER) @@ -1090,7 +1077,7 @@ HRESULT ClrDataAccess::GetMethodDescData( } } } - } + } } } @@ -1098,6 +1085,126 @@ HRESULT ClrDataAccess::GetMethodDescData( return hr; } +HRESULT ClrDataAccess::GetTieredVersions( + CLRDATA_ADDRESS methodDesc, + int rejitId, + struct DacpTieredVersionData *nativeCodeAddrs, + int cNativeCodeAddrs, + int *pcNativeCodeAddrs) +{ + if (methodDesc == 0 || cNativeCodeAddrs == 0 || pcNativeCodeAddrs == NULL) + { + return E_INVALIDARG; + } + + *pcNativeCodeAddrs = 0; + + SOSDacEnter(); + +#ifdef FEATURE_REJIT + PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc)); + + // If rejit info is appropriate, get the following: + // * ReJitInfo for the current, active version of the method + // * ReJitInfo for the requested IP (for !ip2md and !u) + // * ReJitInfos for all reverted versions of the method (up to + // cRevertedRejitVersions) + // + // Minidumps will not have all this rejit info, and failure to get rejit info + // should not be fatal. So enclose all rejit stuff in a try. + + EX_TRY + { + CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager(); + + // Total number of jitted rejit versions + ULONG cJittedRejitVersions; + if (!SUCCEEDED(ReJitManager::GetReJITIDs(pMD, 0 /* cReJitIds */, &cJittedRejitVersions, NULL /* reJitIds */))) + { + goto cleanup; + } + + if ((ULONG)rejitId >= cJittedRejitVersions) + { + hr = E_INVALIDARG; + goto cleanup; + } + + ULONG cReJitIds; + StackSArray reJitIds; + + // Prepare array to populate with rejitids. + ReJITID *rgReJitIds = reJitIds.OpenRawBuffer(cJittedRejitVersions); + if (rgReJitIds != NULL) + { + hr = ReJitManager::GetReJITIDs(pMD, cJittedRejitVersions, &cReJitIds, rgReJitIds); + if (SUCCEEDED(hr)) + { + reJitIds.CloseRawBuffer(cReJitIds); + + ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitIds[rejitId]); + + if (ilCodeVersion.IsNull()) + { + hr = S_FALSE; + goto cleanup; + } + + NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD); + int count = 0; + for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++) + { + nativeCodeAddrs[count].NativeCodeAddr = (*iter).GetNativeCode(); + PTR_NativeCodeVersionNode pNode = (*iter).AsNode(); + nativeCodeAddrs[count].NativeCodeVersionNodePtr = TO_CDADDR(PTR_TO_TADDR(pNode)); + + if (pMD->IsEligibleForTieredCompilation()) + { + switch ((*iter).GetOptimizationTier()) + { + default: + nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::TIERED_UNKNOWN; + break; + case NativeCodeVersion::OptimizationTier0: + nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::TIERED_0; + break; + case NativeCodeVersion::OptimizationTier1: + nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::TIERED_1; + break; + } + } + else + { + nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::NON_TIERED; + } + + ++count; + + if (count >= cNativeCodeAddrs) + { + hr = S_FALSE; + break; + } + } + + *pcNativeCodeAddrs = count; + } + } + } + EX_CATCH + { + hr = E_FAIL; + } + EX_END_CATCH(SwallowAllExceptions) + +cleanup: + ; +#endif // FEATURE_REJIT + + SOSDacLeave(); + return hr; +} + HRESULT ClrDataAccess::GetMethodDescTransparencyData(CLRDATA_ADDRESS methodDesc, struct DacpMethodDescTransparencyData *data) { diff --git a/src/inc/dacprivate.h b/src/inc/dacprivate.h index a419c47..2f74826 100644 --- a/src/inc/dacprivate.h +++ b/src/inc/dacprivate.h @@ -507,7 +507,8 @@ struct MSLAYOUT DacpReJitData : ZeroInit Flags flags; CLRDATA_ADDRESS NativeCodeAddr; }; - + + struct MSLAYOUT DacpMethodDescData : ZeroInit { BOOL bHasNativeCode; @@ -552,6 +553,7 @@ struct MSLAYOUT DacpMethodDescData : ZeroInit } }; + struct MSLAYOUT DacpMethodDescTransparencyData : ZeroInit { BOOL bHasCriticalTransparentInfo; @@ -564,6 +566,21 @@ struct MSLAYOUT DacpMethodDescTransparencyData : ZeroInitlpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISOSDacInterface5_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISOSDacInterface5_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISOSDacInterface5_GetTieredVersions(This,methodDesc,rejitId,nativeCodeAddrs,cNativeCodeAddrs) \ + ( (This)->lpVtbl -> GetTieredVersions(This,methodDesc,rejitId,nativeCodeAddrs,cNativeCodeAddrs) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISOSDacInterface5_INTERFACE_DEFINED__ */ + /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */ diff --git a/src/vm/codeversion.h b/src/vm/codeversion.h index 7bb2a24..768c9cd 100644 --- a/src/vm/codeversion.h +++ b/src/vm/codeversion.h @@ -492,7 +492,7 @@ public: return (count_t)(size_t)dac_cast(k); } - static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t(); } + static const element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast(nullptr); } static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; } }; @@ -554,7 +554,7 @@ public: return (count_t)k.Hash(); } - static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t(); } + static const element_t Null() { LIMITED_METHOD_CONTRACT; return dac_cast(nullptr); } static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; } }; -- 2.7.4