diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp index a34b5924ee741b..6f06bcec1fc679 100644 --- a/src/coreclr/debug/createdump/crashinfo.cpp +++ b/src/coreclr/debug/createdump/crashinfo.cpp @@ -379,9 +379,33 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(DumpType dumpType) TRACE("EnumerateMemoryRegionsWithDAC: Memory enumeration STARTED (%d %d)\n", m_enumMemoryPagesAdded, m_dataTargetPagesAdded); // CLRDATA_ENUM_MEM_HEAP2 skips the expensive (in both time and memory usage) enumeration of the - // low level data structures and adds all the loader allocator heaps instead. + // low level data structures and adds all the loader allocator heaps instead. The older 'DbgEnableFastHeapDumps' + // env var didn't generate a complete enough heap dump on Linux and this new path does. CLRDataEnumMemoryFlags flags = CLRDATA_ENUM_MEM_HEAP2; MINIDUMP_TYPE minidumpType = GetMiniDumpType(dumpType); + if (dumpType == DumpType::Heap) + { + // This is the old fast heap env var for backwards compatibility for VS4Mac. + CLRConfigNoCache fastHeapDumps = CLRConfigNoCache::Get("DbgEnableFastHeapDumps", /*noprefix*/ false, &getenv); + DWORD val = 0; + if (fastHeapDumps.IsSet() && fastHeapDumps.TryAsInteger(10, val) && val == 1) + { + // Since on MacOS all the RW regions will be added for heap dumps by createdump, the + // only thing differentiating a MiniDumpNormal and a MiniDumpWithPrivateReadWriteMemory + // is that the later uses the EnumMemoryRegions APIs. This is kind of expensive on larger + // applications (4 minutes, or even more), and this should already be in RW pages. Change + // the dump type to the faster normal one. This one already ensures necessary DAC globals, + // etc. without the costly assembly, module, class, type runtime data structures enumeration. + minidumpType = MiniDumpNormal; + flags = CLRDATA_ENUM_MEM_DEFAULT; + } + // This env var allows the CLRDATA_ENUM_MEM_HEAP2 fast path to be opt-ed out + fastHeapDumps = CLRConfigNoCache::Get("EnableFastHeapDumps", /*noprefix*/ false, &getenv); + if (fastHeapDumps.IsSet() && fastHeapDumps.TryAsInteger(10, val) && val == 0) + { + flags = CLRDATA_ENUM_MEM_DEFAULT; + } + } // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC HRESULT hr = m_pClrDataEnumRegions->EnumMemoryRegions(this, minidumpType, flags); if (FAILED(hr)) diff --git a/src/coreclr/debug/daccess/enummem.cpp b/src/coreclr/debug/daccess/enummem.cpp index 23d30c832c4658..a329019ae051dc 100644 --- a/src/coreclr/debug/daccess/enummem.cpp +++ b/src/coreclr/debug/daccess/enummem.cpp @@ -1861,9 +1861,9 @@ HRESULT ClrDataAccess::EnumMemWriteDataSegment() //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // -// Custom dumps enumerate the minimal CLR state needed for -// MiniDumpWithFullAuxiliaryState: thread stacks, modules, CLR statics, and any -// memory reached implicitly from those roots. +// Custom Dump. Depending on the value of g_ECustomDumpFlavor, different dump +// will be taken. You can set this global variable using hosting API +// ICLRErrorReportingManager::BeginCustomDump. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerCustom() @@ -1871,41 +1871,87 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerCustom() SUPPORTS_DAC; HRESULT status = S_OK; + + ECustomDumpFlavor eFlavor; + + eFlavor = DUMP_FLAVOR_Default; + m_enumMemFlags = CLRDATA_ENUM_MEM_MINI; // clear all of the previous cached memory Flush(); - // Iterating to all threads' stacks - CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(m_enumMemFlags); ) - if (FAILED(status)) + if (eFlavor == DUMP_FLAVOR_Mini) { - return status; - } + // Iterating to all threads' stacks + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(m_enumMemFlags); ) - // Iterating to module list. - CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(m_enumMemFlags); ) - if (FAILED(status)) - { - return status; - } + // Iterating to module list. + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(m_enumMemFlags); ) - // - // iterating through static that we care - // - // collect CLR static - CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); ) - if (FAILED(status)) + // + // iterating through static that we care + // + // collect CLR static + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); ) + + // we are done... + + // now dump the memory get dragged in implicitly + m_dumpStats.m_cbImplicitly = m_instances.DumpAllInstances(m_enumMemCb); + + } + else if (eFlavor == DUMP_FLAVOR_CriticalCLRState) { - return status; + // We need to walk Threads stack to view managed frames. + // Iterating through module list + + // Iterating to all threads' stacks + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(m_enumMemFlags); ) + + // Iterating to module list. + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(m_enumMemFlags); ) + + // + // iterating through static that we care + // + // collect CLR static + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); ) + + // Collecting some CLR secondary critical data + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRHeapCrticalStatic(m_enumMemFlags); ) + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemWriteDataSegment(); ) + + // we are done... + + // now dump the memory get dragged in implicitly + m_dumpStats.m_cbImplicitly = m_instances.DumpAllInstances(m_enumMemCb); + } + else if (eFlavor == DUMP_FLAVOR_NonHeapCLRState) + { + // since all CLR hosted heap will be dump by the host, + // the EE structures that are not loaded using LoadLibrary will + // be included by the host. + // + // Thus we only need to include mscorwks's critical data and ngen images - // we are done... + m_enumMemFlags = CLRDATA_ENUM_MEM_HEAP; - // now dump the memory get dragged in implicitly - m_dumpStats.m_cbImplicitly = m_instances.DumpAllInstances(m_enumMemCb); + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); ) - return status; + // Collecting some CLR secondary critical data + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRHeapCrticalStatic(m_enumMemFlags); ) + + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemWriteDataSegment(); ) + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCollectImages(); ) + } + else + { + status = E_INVALIDARG; + } + + return S_OK; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -1949,7 +1995,7 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWrapper(IN CLRDataEnumMemoryFlags flags) // triage micro-dump status = EnumMemoryRegionsWorkerMicroTriage(flags); } - else if (flags == CLRDATA_ENUM_MEM_HEAP2) + else if (flags == CLRDATA_ENUM_MEM_HEAP || flags == CLRDATA_ENUM_MEM_HEAP2) { status = EnumMemoryRegionsWorkerHeap(flags); } @@ -2041,7 +2087,16 @@ ClrDataAccess::EnumMemoryRegions(IN ICLRDataEnumMemoryRegionsCallback* callback, ClearDumpStats(); if (miniDumpFlags & MiniDumpWithPrivateReadWriteMemory) { - status = EnumMemoryRegionsWrapper(CLRDATA_ENUM_MEM_HEAP2); + // heap dump + if (flags == CLRDATA_ENUM_MEM_HEAP2) + { + DacLogMessage("EnumMemoryRegions(CLRDATA_ENUM_MEM_HEAP2)\n"); + } + else + { + flags = CLRDATA_ENUM_MEM_HEAP; + } + status = EnumMemoryRegionsWrapper(flags); } else if (miniDumpFlags & MiniDumpWithFullAuxiliaryState) { diff --git a/src/coreclr/debug/ee/functioninfo.cpp b/src/coreclr/debug/ee/functioninfo.cpp index 6ad138388ee0a5..69c5d81351d897 100644 --- a/src/coreclr/debug/ee/functioninfo.cpp +++ b/src/coreclr/debug/ee/functioninfo.cpp @@ -2435,6 +2435,16 @@ DebuggerMethodInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) DAC_ENUM_DTHIS(); SUPPORTS_DAC; + if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE && flags != CLRDATA_ENUM_MEM_HEAP2) + { + // Modules are enumerated already for minidumps, save the empty calls. + if (m_module.IsValid()) + { + m_module->EnumMemoryRegions(flags, true); + } + + } + PTR_DebuggerJitInfo jitInfo = m_latestJitInfo; while (jitInfo.IsValid()) { @@ -2454,6 +2464,19 @@ DebuggerJitInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) m_methodInfo->EnumMemoryRegions(flags); } + if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE && flags != CLRDATA_ENUM_MEM_HEAP2) + { + if (m_nativeCodeVersion.GetMethodDesc().IsValid()) + { + m_nativeCodeVersion.GetMethodDesc()->EnumMemoryRegions(flags); + } + + DacEnumMemoryRegion(PTR_TO_TADDR(GetSequenceMap()), + GetSequenceMapCount() * sizeof(DebuggerILToNativeMap)); + DacEnumMemoryRegion(PTR_TO_TADDR(GetVarNativeInfo()), + GetVarNativeInfoCount() * + sizeof(ICorDebugInfo::NativeVarInfo)); + } } diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 5f2526172d941d..36c0084ef376fc 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -1881,6 +1881,21 @@ Assembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) { GetLoaderAllocator()->EnumMemoryRegions(flags); } + else + { + if (m_pClassLoader.IsValid()) + { + m_pClassLoader->EnumMemoryRegions(flags); + } + if (m_pModule.IsValid()) + { + m_pModule->EnumMemoryRegions(flags, true); + } + if (m_pPEAssembly.IsValid()) + { + m_pPEAssembly->EnumMemoryRegions(flags); + } + } } #else // DACCESS_COMPILE diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index a729f1b240846e..b793b03248a569 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -4522,6 +4522,79 @@ void Module::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, { GetLoaderAllocator()->EnumMemoryRegions(flags); } + else if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE) + { + if (m_pAvailableClasses.IsValid()) + { + m_pAvailableClasses->EnumMemoryRegions(flags); + } + if (m_pAvailableParamTypes.IsValid()) + { + m_pAvailableParamTypes->EnumMemoryRegions(flags); + } + if (m_pInstMethodHashTable.IsValid()) + { + m_pInstMethodHashTable->EnumMemoryRegions(flags); + } + if (m_pAvailableClassesCaseIns.IsValid()) + { + m_pAvailableClassesCaseIns->EnumMemoryRegions(flags); + } + + // Save the LookupMap structures. + m_MethodDefToDescMap.ListEnumMemoryRegions(flags); + m_FieldDefToDescMap.ListEnumMemoryRegions(flags); + m_MemberRefMap.ListEnumMemoryRegions(flags); + m_GenericParamToDescMap.ListEnumMemoryRegions(flags); + m_ManifestModuleReferencesMap.ListEnumMemoryRegions(flags); + + LookupMap::Iterator typeDefIter(&m_TypeDefToMethodTableMap); + while (typeDefIter.Next()) + { + if (typeDefIter.GetElement()) + { + typeDefIter.GetElement()->EnumMemoryRegions(flags); + } + } + + LookupMap::Iterator typeRefIter(&m_TypeRefToMethodTableMap); + while (typeRefIter.Next()) + { + if (typeRefIter.GetElement()) + { + TypeHandle th = TypeHandle::FromTAddr(dac_cast(typeRefIter.GetElement())); + th.EnumMemoryRegions(flags); + } + } + + LookupMap::Iterator methodDefIter(&m_MethodDefToDescMap); + while (methodDefIter.Next()) + { + if (methodDefIter.GetElement()) + { + methodDefIter.GetElement()->EnumMemoryRegions(flags); + } + } + + LookupMap::Iterator fieldDefIter(&m_FieldDefToDescMap); + while (fieldDefIter.Next()) + { + if (fieldDefIter.GetElement()) + { + fieldDefIter.GetElement()->EnumMemoryRegions(flags); + } + } + + LookupMap::Iterator genericParamIter(&m_GenericParamToDescMap); + while (genericParamIter.Next()) + { + if (genericParamIter.GetElement()) + { + genericParamIter.GetElement()->EnumMemoryRegions(flags); + } + } + + } // !CLRDATA_ENUM_MEM_MINI && !CLRDATA_ENUM_MEM_TRIAGE && !CLRDATA_ENUM_MEM_HEAP2 LookupMap::Iterator asmRefIter(&m_ManifestModuleReferencesMap); while (asmRefIter.Next()) diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 1a37e2346b0dbe..d1a2c67c19554b 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -3369,6 +3369,21 @@ EEClass::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, MethodTable * pMT) if (HasOptionalFields()) DacEnumMemoryRegion(dac_cast(GetOptionalFields()), sizeof(EEClassOptionalFields)); + if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE && flags != CLRDATA_ENUM_MEM_HEAP2) + { + PTR_Module pModule = pMT->GetModule(); + if (pModule.IsValid()) + { + pModule->EnumMemoryRegions(flags, true); + } + PTR_MethodDescChunk chunk = GetChunks(); + while (chunk.IsValid()) + { + chunk->EnumMemoryRegions(flags); + chunk = chunk->GetNextChunk(); + } + } + PTR_FieldDesc pFieldDescList = GetFieldDescList(); if (pFieldDescList.IsValid()) { diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 5a5a714a360edf..79f080cc339280 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -7788,6 +7788,14 @@ MethodTable::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) } } + if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE && flags != CLRDATA_ENUM_MEM_HEAP2) + { + DispatchMap * pMap = GetDispatchMap(); + if (pMap != NULL) + { + pMap->EnumMemoryRegions(flags); + } + } } // MethodTable::EnumMemoryRegions #endif // DACCESS_COMPILE diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index ae61f430add3de..292e5621b2e373 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -6784,6 +6784,10 @@ Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) WRAPPER_NO_CONTRACT; DAC_ENUM_DTHIS(); + if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE && flags != CLRDATA_ENUM_MEM_HEAP2) + { + AppDomain::GetCurrentDomain()->EnumMemoryRegions(flags, true); + } if (m_debuggerFilterContext.IsValid()) { @@ -6871,6 +6875,11 @@ Thread::EnumMemoryRegionsWorker(CLRDataEnumMemoryFlags flags) DacGetThreadContext(this, &context); } + if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE && flags != CLRDATA_ENUM_MEM_HEAP2) + { + AppDomain::GetCurrentDomain()->EnumMemoryRegions(flags, true); + } + FillRegDisplay(®Disp, &context); frameIter.Init(this, NULL, ®Disp, 0); while (frameIter.IsValid()) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 6172fe6fdf295c..5bfcc075bb5d13 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -89,7 +89,7 @@ CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out try { Guid iidMetaDataImport = typeof(IMetaDataImport).GUID; - if (_legacyModulePointer != 0 && Marshal.QueryInterface(_legacyModulePointer, iidMetaDataImport, out nint ppMdi) >= 0) + if (_legacyModulePointer != 0 && _legacyModulePointer != 1 && Marshal.QueryInterface(_legacyModulePointer, iidMetaDataImport, out nint ppMdi) >= 0) { legacyImport = ComInterfaceMarshaller.ConvertToManaged((void*)ppMdi); Marshal.Release(ppMdi);