From b126b9a50434ffb164b1e2db21ba85915db38c8e Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 21 Nov 2023 11:05:52 -0800 Subject: [PATCH] Store entry assembly path for easy access for diagnostics (#95045) - Add `g_EntryAssemblyPath` global variable holding the full path to the entry assembly - Set right before loading the entry assembly (so also before startup hooks are run) - NULL if there is no entry assembly - Ensure value is included dumps - For triage dumps, the dumped value is updated to only be the assembly file name instead of the full path --- src/coreclr/debug/daccess/enummem.cpp | 28 +++++++++++++++++++++++++++ src/coreclr/inc/daccess.h | 6 ++++-- src/coreclr/inc/dacvars.h | 2 ++ src/coreclr/vm/corhost.cpp | 9 +++++++++ src/coreclr/vm/vars.cpp | 2 ++ src/coreclr/vm/vars.hpp | 3 +++ 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/daccess/enummem.cpp b/src/coreclr/debug/daccess/enummem.cpp index 44d98beec2de3..7856a1ff0c096 100644 --- a/src/coreclr/debug/daccess/enummem.cpp +++ b/src/coreclr/debug/daccess/enummem.cpp @@ -224,6 +224,34 @@ HRESULT ClrDataAccess::EnumMemCLRStatic(IN CLRDataEnumMemoryFlags flags) ReportMem(g_gcDacGlobals.GetAddr(), sizeof(GcDacVars)); + PTR_WSTR entryAssemblyPath = (PTR_WSTR)g_EntryAssemblyPath; + entryAssemblyPath.EnumMem(); + + // Triage dumps must not include full paths (PII data). Replace entry assembly path with file name only. + if (flags == CLRDATA_ENUM_MEM_TRIAGE) + { + WCHAR* path = entryAssemblyPath; + if (path != NULL) + { + size_t pathLen = u16_strlen(path) + 1; + + // Get the file name based on the last directory separator + const WCHAR* name = u16_strrchr(path, DIRECTORY_SEPARATOR_CHAR_W); + if (name != NULL) + { + name += 1; + size_t len = u16_strlen(name) + 1; + wcscpy_s(path, len, name); + + // Null out the rest of the buffer + for (size_t i = len; i < pathLen; ++i) + path[i] = W('\0'); + + DacUpdateMemoryRegion(entryAssemblyPath.GetAddr(), pathLen, (BYTE*)path); + } + } + } + // We need all of the dac variables referenced by the GC DAC global struct. // This struct contains pointers to pointers, so we first dereference the pointers // to obtain the location of the variable that's reported. diff --git a/src/coreclr/inc/daccess.h b/src/coreclr/inc/daccess.h index 3ca0ca40ee42e..54ce86551caee 100644 --- a/src/coreclr/inc/daccess.h +++ b/src/coreclr/inc/daccess.h @@ -574,6 +574,8 @@ #include "crosscomp.h" #endif +#include + // Information stored in the DAC table of interest to the DAC implementation // Note that this information is shared between all instantiations of ClrDataAccess, so initialize // it just once in code:ClrDataAccess.GetDacGlobals (rather than use fields in ClrDataAccess); @@ -1493,10 +1495,10 @@ class __Str16Ptr : public __DPtr } void EnumMem(void) const { - char* str = DacInstantiateStringW(m_addr, maxChars, false); + WCHAR* str = DacInstantiateStringW(m_addr, maxChars, false); if (str) { - DacEnumMemoryRegion(m_addr, strlen(str) + 1); + DacEnumMemoryRegion(m_addr, u16_strlen(str) + 1); } } }; diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 8fcc1cced7d43..030c18f0b9db2 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -231,5 +231,7 @@ DEFINE_DACVAR(SIZE_T, dac__g_clrNotificationArguments, ::g_clrNotificationArgume DEFINE_DACVAR(bool, dac__g_metadataUpdatesApplied, ::g_metadataUpdatesApplied) #endif +DEFINE_DACVAR(PTR_WSTR, dac__g_EntryAssemblyPath, ::g_EntryAssemblyPath) + #undef DEFINE_DACVAR #undef DEFINE_DACVAR_NO_DUMP diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index bb32e93cd0961..b85331e00ce8d 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -310,6 +310,15 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, _ASSERTE (!pThread->PreemptiveGCDisabled()); + if (g_EntryAssemblyPath == NULL) + { + // Store the entry assembly path for diagnostic purposes (for example, dumps) + size_t len = u16_strlen(pwzAssemblyPath) + 1; + NewArrayHolder path { new WCHAR[len] }; + wcscpy_s(path, len, pwzAssemblyPath); + g_EntryAssemblyPath = path.Extract(); + } + Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath); #if defined(FEATURE_MULTICOREJIT) diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index 85737057d2f9c..00840f9195651 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -106,6 +106,8 @@ GVAL_IMPL_INIT(DWORD, g_debuggerWordTLSIndex, TLS_OUT_OF_INDEXES); #endif GVAL_IMPL_INIT(DWORD, g_TlsIndex, TLS_OUT_OF_INDEXES); +GVAL_IMPL_INIT(PTR_WSTR, g_EntryAssemblyPath, NULL); + #ifndef DACCESS_COMPILE // @TODO - PROMOTE. diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index dd92ee7b12fde..03762a24e695d 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -389,6 +389,9 @@ GVAL_DECL(DWORD, g_debuggerWordTLSIndex); #endif GVAL_DECL(DWORD, g_TlsIndex); +// Full path to the managed entry assembly - stored for ease of identifying the entry asssembly for diagnostics +GVAL_DECL(PTR_WSTR, g_EntryAssemblyPath); + // Global System Information extern SYSTEM_INFO g_SystemInfo;