2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
10 // ICLRDataEnumMemoryRegions implementation.
12 //*****************************************************************************
18 #include <gcinfodecoder.h>
20 #include "typestring.h"
22 #include "ipcmanagerinterface.h"
24 #include "win32threadpool.h"
29 #endif // FEATURE_APPX
31 #if defined(DAC_MEASURE_PERF)
33 unsigned __int64 g_nTotalTime;
34 unsigned __int64 g_nStackTotalTime;
35 unsigned __int64 g_nReadVirtualTotalTime;
36 unsigned __int64 g_nFindTotalTime;
37 unsigned __int64 g_nFindHashTotalTime;
38 unsigned __int64 g_nFindHits;
39 unsigned __int64 g_nFindCalls;
40 unsigned __int64 g_nFindFails;
41 unsigned __int64 g_nStackWalk;
42 unsigned __int64 g_nFindStackTotalTime;
44 #endif // #if defined(DAC_MEASURE_PERF)
48 // EnumMemCollectImages - collect all images of interest for heap dumps
50 // This is used primarily to save ngen images.
51 // This is necessary so that heap dumps contain the full native code for the
52 // process. Normally mini/heap dump debugging requires that the images be
53 // available at debug-time, (in fact, watson explicitly does not want to
54 // be downloading 3rd party images). Not including images is the main size
55 // advantage of heap dumps over full dumps. However, since ngen images are
56 // produced on the client, we can't always ensure that the debugger will
57 // have access to the exact ngen image used in the dump. Therefore, managed
58 // heap dumps also include full copies of all NGen images in the process.
60 // We also currently include in-memory modules (provided by a host, or loaded
63 HRESULT ClrDataAccess::EnumMemCollectImages()
67 ProcessModIter modIter;
68 Module* modDef = NULL;
69 HRESULT status = S_OK;
75 TSIZE_T cbMemoryReported = m_cbMemoryReported;
78 // Collect the ngen images - Iterating through module list
82 while ((modDef = modIter.NextModule()))
87 file = modDef->GetFile();
89 // We want to save all native images
90 if (file->HasNativeImage())
92 // We should only skip if signed by Microsoft!
93 pStartAddr = PTR_TO_TADDR(file->GetLoadedNative()->GetBase());
94 ulSize = file->GetLoadedNative()->GetSize();
96 // We also want to save any in-memory images. These show up like mapped files
97 // and so would not be in a heap dump by default. Technically it's not clear we
98 // should include them in the dump - you can often have the files available
99 // after-the-fact. But in-memory modules may be harder to track down at debug time
100 // and people may have come to rely on this - so we'll include them for now.
103 // With Copy On Write feature enabled
104 // IL images would not be dumped as part of the private pages.
105 // We need to explicitly dump them here.
106 #ifndef FEATURE_LAZY_COW_PAGES
107 file->GetPath().IsEmpty() && // is in-memory
108 #endif // FEATURE_LAZY_COW_PAGES
109 file->HasMetadata() && // skip resource assemblies
110 file->IsLoaded(FALSE) && // skip files not yet loaded
111 !file->IsDynamic()) // skip dynamic (GetLoadedIL asserts anyway)
113 pStartAddr = PTR_TO_TADDR(file->GetLoadedIL()->GetBase());
114 ulSize = file->GetLoadedIL()->GetSize();
117 // memory are mapped in in OS_PAGE_SIZE size.
118 // Some memory are mapped in but some are not. You cannot
119 // write all in one block. So iterating through page size
124 // Note that we have talked about not writing IL and Metadata to save size.
125 // It turns out IL was rarely mapped in.
126 // Metadata is needed. The RVA field is needed for it is pointed to a
127 // MethodHeader MethodDesc::GetILHeader. Without this RVA,
128 // all locals are broken. In case, you are asked about this question again.
130 ulSizeBlock = ulSize > OS_PAGE_SIZE ? OS_PAGE_SIZE : ulSize;
131 ReportMem(pStartAddr, ulSizeBlock, false);
132 pStartAddr += ulSizeBlock;
133 ulSize -= ulSizeBlock;
136 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
139 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
141 m_dumpStats.m_cbNgen = m_cbMemoryReported - cbMemoryReported;
147 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
149 // collecting memory for mscorwks's heap dump critical statics
150 // This include the stress log, config structure, and IPC block
152 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
153 HRESULT ClrDataAccess::EnumMemCLRHeapCrticalStatic(IN CLRDataEnumMemoryFlags flags)
157 TSIZE_T cbMemoryReported = m_cbMemoryReported;
159 // Write out the stress log structure itself
160 DacEnumHostDPtrMem(g_pStressLog);
162 // This is pointing to a static buffer
163 DacEnumHostDPtrMem(g_pConfig);
165 // dump GC heap structures. Note that the managed heap is not dumped out.
166 // We are just dump the GC heap structures.
168 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( EnumWksGlobalMemoryRegions(flags); );
169 #ifdef FEATURE_SVR_GC
170 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( EnumSvrGlobalMemoryRegions(flags); );
173 #ifdef FEATURE_IPCMAN
175 // Write Out IPC Blocks
179 g_pIPCManagerInterface.EnumMem();
180 if (g_pIPCManagerInterface.IsValid())
182 // write out the instance
183 DacEnumHostDPtrMem(g_pIPCManagerInterface);
185 // Then write out the public and private block
186 ReportMem(PTR_TO_TADDR(g_pIPCManagerInterface->GetBlockStart()), g_pIPCManagerInterface->GetBlockSize());
187 ReportMem(PTR_TO_TADDR(g_pIPCManagerInterface->GetBlockTableStart()), g_pIPCManagerInterface->GetBlockTableSize());
190 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
191 #endif // FEATURE_IPCMAN
193 m_dumpStats.m_cbClrHeapStatics = m_cbMemoryReported - cbMemoryReported;
198 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
200 // collecting memory for mscorwks's statics. This is the minimal
201 // set of global and statics that we need to have !threads, !pe, !ClrStack
204 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
205 HRESULT ClrDataAccess::EnumMemCLRStatic(IN CLRDataEnumMemoryFlags flags)
209 TSIZE_T cbMemoryReported = m_cbMemoryReported;
212 // write out the static and global content that we care.
215 // The followig macro will report memory all of the dac related mscorwks static and
216 // global variables. But it won't report the structures that are pointed by
219 #define DEFINE_DACVAR(id_type, size_type, id, var) \
220 ReportMem(m_globalBase + g_dacGlobals.id, sizeof(size_type));
222 #define DEFINE_DACVAR_SVR(id_type, size_type, id, var) \
223 ReportMem(m_globalBase + g_dacGlobals.id, sizeof(size_type));
225 // Cannot use CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
226 // around conditional preprocessor directives in a sane fashion.
233 // Catch the exception and keep going unless COR_E_OPERATIONCANCELED
234 // was thrown. Used generating dumps, where rethrow will cancel dump.
236 EX_END_CATCH(RethrowCancelExceptions)
238 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
240 // StressLog is not defined on Rotor build for DAC
241 ReportMem(m_globalBase + g_dacGlobals.dac__g_pStressLog, sizeof(StressLog *));
246 // These two static pointers are pointed to static data of byte[]
247 // then run constructor in place
249 ReportMem(m_globalBase + g_dacGlobals.SystemDomain__m_pSystemDomain,
250 sizeof(SystemDomain));
251 ReportMem(m_globalBase + g_dacGlobals.SharedDomain__m_pSharedDomain,
252 sizeof(SharedDomain));
254 // We need GCHeap pointer to make EEVersion work
255 ReportMem(m_globalBase + g_dacGlobals.dac__g_pGCHeap,
258 // see synblk.cpp, the pointer is pointed to a static byte[]
259 SyncBlockCache::s_pSyncBlockCache.EnumMem();
261 #ifndef FEATURE_IMPLICIT_TLS
262 ReportMem(m_globalBase + g_dacGlobals.dac__gThreadTLSIndex,
264 ReportMem(m_globalBase + g_dacGlobals.dac__gAppDomainTLSIndex,
268 ReportMem( m_globalBase + g_dacGlobals.dac__g_FCDynamicallyAssignedImplementations,
269 sizeof(TADDR)*ECall::NUM_DYNAMICALLY_ASSIGNED_FCALL_IMPLEMENTATIONS);
271 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
274 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_runtimeLoadedBaseAddress.EnumMem(); )
275 #endif // !FEATURE_PAL
277 // These are the structures that are pointed by global pointers and we care.
278 // Some may reside in heap and some may reside as a static byte array in mscorwks.dll
279 // That is ok. We will report them explicitly.
281 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pConfig.EnumMem(); )
282 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pPredefinedArrayTypes.EnumMem(); )
283 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pObjectClass.EnumMem(); )
284 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pStringClass.EnumMem(); )
285 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pArrayClass.EnumMem(); )
286 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pExceptionClass.EnumMem(); )
287 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pThreadAbortExceptionClass.EnumMem(); )
288 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pOutOfMemoryExceptionClass.EnumMem(); )
289 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pStackOverflowExceptionClass.EnumMem(); )
290 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pExecutionEngineExceptionClass.EnumMem(); )
291 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDelegateClass.EnumMem(); )
292 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pMulticastDelegateClass.EnumMem(); )
293 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pValueTypeClass.EnumMem(); )
294 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pEnumClass.EnumMem(); )
295 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pThreadClass.EnumMem(); )
296 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pCriticalFinalizerObjectClass.EnumMem(); )
297 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pFreeObjectMethodTable.EnumMem(); )
298 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pObjectCtorMD.EnumMem(); )
299 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_fHostConfig.EnumMem(); )
301 // These two static pointers are pointed to static data of byte[]
302 // then run constructor in place
304 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( SystemDomain::m_pSystemDomain.EnumMem(); )
305 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( SharedDomain::m_pSharedDomain.EnumMem(); )
306 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugger.EnumMem(); )
307 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pEEInterface.EnumMem(); )
308 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugInterface.EnumMem(); )
309 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pEEDbgInterfaceImpl.EnumMem(); )
310 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_CORDebuggerControlFlags.EnumMem(); )
311 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_Mscorlib.EnumMem(); )
312 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT]->EnumMemoryRegions(flags); )
313 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( StubManager::EnumMemoryRegions(flags); )
314 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pFinalizerThread.EnumMem(); )
315 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pSuspensionThread.EnumMem(); )
317 #ifdef FEATURE_SVR_GC
318 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
320 GCHeap::gcHeapType.EnumMem();
322 #endif // FEATURE_SVR_GC
324 m_dumpStats.m_cbClrStatics = m_cbMemoryReported - cbMemoryReported;
329 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
331 // This function reports memory that a heap dump need to debug CLR
332 // and managed code efficiently.
334 // We will write out -
335 // 1. mscorwks.dll's image read/write pages
336 // 2. IPC blocks - shared memory (needed for debugging service and perf counter)
337 // 3. ngen images excluding Metadata and IL for size perf
338 // 4. We may want to touch the code pages on the stack - to be safe....
340 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
341 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerHeap(IN CLRDataEnumMemoryFlags flags)
345 HRESULT status = S_OK;
347 m_instances.ClearEnumMemMarker();
349 // clear all of the previous cached memory
352 // collect ngen image
353 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCollectImages(); );
355 // collect CLR static
356 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(flags); );
357 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRHeapCrticalStatic(flags); );
359 // Note that we do not need to flush out all of the dac instance manager's instance.
360 // This is because it is a heap dump here. Assembly and AppDomain objects will be reported
361 // by the default heap collection mechanism by dbghelp.lib
363 // Microsoft: I suspect if we have all private read-write pages the preceding statement
364 // would be true, but I don't think we have that guarantee here.
365 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(flags); );
367 #ifdef FEATURE_LAZY_COW_PAGES
368 // Iterating to all threads' stacks, as we have to collect data stored inside (core)clr.dll
369 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(flags); )
371 // Dump AppDomain-specific info
372 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAppDomainInfo(flags); )
374 // Dump the Debugger object data needed
375 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugger->EnumMemoryRegions(flags); )
377 // now dump the memory get dragged in by using DAC API implicitly.
378 m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
379 #endif // FEATURE_LAZY_COW_PAGES
382 status = m_memStatus;
385 } // EnumMemoryRegionsWorkerHeap
387 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
389 // Helper function for skinny mini-dump
390 // Pass in an managed object, this function will dump the EEClass hierachy
391 // and field desc of object so SOS's !DumpObj will work
394 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
395 HRESULT ClrDataAccess::DumpManagedObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef)
399 HRESULT status = S_OK;
406 if (!CNameSpace::GetGcRuntimeStructuresValid ())
408 // GC is in progress, don't dump this object
414 // write out the current EE class and the direct/indirect inherited EE Classes
415 MethodTable *pMethodTable = objRef->GetGCSafeMethodTable();
421 pMethodTable->EnumMemoryRegions(flags);
425 // This might look odd. We are not using variable s after forming it.
426 // That is because our DAC inspecting API is using TypeString to form
427 // full type name. Form the full name here is a implicit reference to needed
430 TypeString::AppendType(s, TypeHandle(pMethodTable), TypeString::FormatNamespace|TypeString::FormatFullInst);
432 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
434 // Walk up to parent MethodTable
435 pMethodTable = pMethodTable->GetParentMethodTable();
438 // now dump the content for the managed object
439 objRef->EnumMemoryRegions();
441 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
447 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
449 // Helper function for skinny mini-dump
450 // Pass in an managed excption object, this function will dump
451 // the managed exception object and some of its fields, such as message, stack trace string,
454 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
455 HRESULT ClrDataAccess::DumpManagedExcepObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef)
464 if (!CNameSpace::GetGcRuntimeStructuresValid ())
466 // GC is in progress, don't dump this object
470 // write out the managed object for exception. This will only write out the
471 // direct field value. After this, we need to visit some selected fields, such as
472 // exception message and stack trace field, and dump out the object referenced via
475 DumpManagedObject(flags, objRef);
477 // If this is not a pre-allocated exception type, then we'll need to dump out enough memory to ensure
478 // that the lookup codepath from the Module to information for the type of this Exception will
479 // be present. Simply dumping the managed object itself isn't enough. Sos doesn't need this.
482 MethodTable * pMethodTable = objRef->GetGCSafeMethodTable();
483 PTR_Module pModule = pMethodTable->GetModule();
484 mdTypeDef exceptionTypeDef = pMethodTable->GetCl();
486 if (TypeFromToken(exceptionTypeDef) != mdtTypeDef)
488 _ASSERTE(!"Module should have contained a TypeDef, dump will likely be missing exception type lookup!");
491 // The lookup from the Module that contains this TypeDef:
492 pModule->LookupTypeDef(RidFromToken(exceptionTypeDef));
494 // If it's a generic class, we need to implicitly enumerate the memory needed to look it up
495 // and enable the calls that ICD will want to make against the TypeHandle when retrieving the
498 th = ClassLoader::LookupTypeDefOrRefInModule(pModule, exceptionTypeDef);
499 th.EnumMemoryRegions(flags);
501 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
503 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
504 // store the exception type name
507 MethodTable * pMethodTable = objRef->GetGCSafeMethodTable();
509 TypeString::AppendType(s, TypeHandle(pMethodTable), TypeString::FormatNamespace|TypeString::FormatFullInst);
510 DacMdCacheAddEEName(dac_cast<TADDR>(pMethodTable), s);
512 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
513 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
515 EXCEPTIONREF exceptRef = (EXCEPTIONREF)objRef;
517 if (flags != CLRDATA_ENUM_MEM_TRIAGE)
519 // dump the exception message field
520 DumpManagedObject(flags, (OBJECTREF)exceptRef->GetMessage());
523 // dump the exception's stack trace field
524 DumpManagedStackTraceStringObject(flags, exceptRef->GetStackTraceString());
526 // dump the exception's remote stack trace field only if we are not generating a triage dump, or
527 // if we are generating a triage dump of an AppX process, or the exception type does not override
528 // the StackTrace getter (see Exception.InternalPreserveStackTrace to understand why)
529 if (flags != CLRDATA_ENUM_MEM_TRIAGE ||
531 AppX::DacIsAppXProcess() ||
532 #endif // FEATURE_APPX
533 !ExceptionTypeOverridesStackTraceGetter(exceptRef->GetGCSafeMethodTable()))
535 DumpManagedStackTraceStringObject(flags, exceptRef->GetRemoteStackTraceString());
538 // Dump inner exception
539 DumpManagedExcepObject(flags, exceptRef->GetInnerException());
541 // Dump the stack trace array object and its underlying type
542 I1ARRAYREF stackTraceArrayObj = exceptRef->GetStackTraceArrayObject();
544 // There are cases where a managed exception does not have a stack trace.
546 // * exception was thrown by VM and no managed frames are on the thread.
547 // * exception thrown is a preallocated exception.
548 if (stackTraceArrayObj != NULL)
550 // first dump the array's element type
551 TypeHandle arrayTypeHandle = stackTraceArrayObj->GetTypeHandle();
552 ArrayTypeDesc* pArrayTypeDesc = arrayTypeHandle.AsArray();
553 TypeHandle elementTypeHandle = pArrayTypeDesc->GetArrayElementTypeHandle();
554 elementTypeHandle.AsMethodTable()->EnumMemoryRegions(flags);
555 elementTypeHandle.AsMethodTable()->GetClass()->EnumMemoryRegions(flags, elementTypeHandle.AsMethodTable());
557 // now dump the actual stack trace array object
558 DumpManagedObject(flags, (OBJECTREF)stackTraceArrayObj);
561 // Dump the stack trace native structure. Unfortunately, we need to write out the
562 // native structure and also dump the MethodDesc that we care about!
563 // We need to ensure the entire _stackTrace from the Exception is enumerated and
564 // included in the dump. When we touch the header and each element looking for the
566 StackTraceArray stackTrace;
567 exceptRef->GetStackTrace(stackTrace);
568 for(size_t i = 0; i < stackTrace.Size(); i++)
570 MethodDesc* pMD = stackTrace[i].pFunc;
571 if (!DacHasMethodDescBeenEnumerated(pMD) && DacValidateMD(pMD))
573 pMD->EnumMemoryRegions(flags);
575 // The following calls are to ensure that mscordacwks!DacDbiInterfaceImpl::GetNativeCodeInfo
576 // will succeed for all dumps.
578 // Pulls in data to translate from token to MethodDesc
579 FindLoadedMethodRefOrDef(pMD->GetMethodTable()->GetModule(), pMD->GetMemberDef());
581 // Pulls in sequence points.
582 DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, pMD);
583 PCODE addr = pMD->GetNativeCode();
586 IJitManager::MethodRegionInfo methodRegionInfo = { NULL, 0, NULL, 0 };
587 EECodeInfo codeInfo(addr);
588 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
592 // Enumerate the code around call site to help SOS resolve the source lines
593 TADDR callEnd = PCODEToPINSTR(stackTrace[i].ip);
594 DacEnumCodeForStackwalk(callEnd);
600 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
602 // Helper function for skinny mini-dump
603 // Pass in a string object representing a managed stack trace, this function will
604 // dump it and "poison" the contents with a PII-free version of the stack trace.
606 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
607 HRESULT ClrDataAccess::DumpManagedStackTraceStringObject(CLRDataEnumMemoryFlags flags, STRINGREF orefStackTrace)
611 if (orefStackTrace == NULL)
616 // dump the stack trace string object
617 DumpManagedObject(flags, (OBJECTREF)orefStackTrace);
619 if (flags == CLRDATA_ENUM_MEM_TRIAGE)
621 // StringObject::GetSString does not support DAC, use GetBuffer/GetStringLength
622 SString stackTrace(dac_cast<PTR_WSTR>((TADDR)orefStackTrace->GetBuffer()), orefStackTrace->GetStringLength());
624 StripFileInfoFromStackTrace(stackTrace);
626 COUNT_T traceCharCount = stackTrace.GetCount();
627 _ASSERTE(traceCharCount <= orefStackTrace->GetStringLength());
629 // fill the rest of the string with \0
630 WCHAR *buffer = stackTrace.OpenUnicodeBuffer(orefStackTrace->GetStringLength());
631 memset(buffer + traceCharCount, 0, sizeof(WCHAR) * (orefStackTrace->GetStringLength() - traceCharCount));
633 // replace the string
634 DacUpdateMemoryRegion(dac_cast<TADDR>(orefStackTrace) + StringObject::GetBufferOffset(), sizeof(WCHAR) * orefStackTrace->GetStringLength(), (BYTE *)buffer);
640 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
642 // Iterating through module list and report the memory.
644 // m_instances.DumpAllInstances(m_enumMemCb);
645 // when all memory enumeration are done if you call this function!
646 // This is because using ProcessModIter will drag in some memory implicitly.
648 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
649 HRESULT ClrDataAccess::EnumMemDumpModuleList(CLRDataEnumMemoryFlags flags)
653 ProcessModIter modIter;
658 TSIZE_T cbMemoryReported = m_cbMemoryReported;
659 #ifdef FEATURE_PREJIT
661 #endif // FEATURE_PREJIT
664 // Iterating through module list
667 // Cannot use CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED around
668 // conditional pre-processor directives in a sane fashion
671 while ((modDef = modIter.NextModule()))
673 // We also want to dump the link from the Module back to the AppDomain,
674 // since the stackwalker uses it to find the AD.
675 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
677 // Pass false to ensure we force enumeration of this module's references.
678 modDef->EnumMemoryRegions(flags, false);
683 // To enable a debugger to check on whether a module is an NI or IL image, they need
684 // the DOS header, PE headers, and IMAGE_COR20_HEADER for the Flags member.
685 // We expose no API today to find this out.
686 PTR_PEFile pPEFile = modDef->GetFile();
687 PEImage * pILImage = pPEFile->GetILimage();
688 PEImage * pNIImage = pPEFile->GetNativeImage();
690 // Implicitly gets the COR header.
691 if ((pILImage) && (pILImage->HasLoadedLayout()))
693 pILImage->GetCorHeaderFlags();
695 if ((pNIImage) && (pNIImage->HasLoadedLayout()))
697 pNIImage->GetCorHeaderFlags();
700 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
705 file = modDef->GetFile();
706 base = PTR_TO_TADDR(file->GetLoadedImageContents(&length));
707 file->EnumMemoryRegions(flags);
708 #ifdef FEATURE_PREJIT
710 // If module has native image and it has debug map, we need to get the debug map.
712 if (modDef->HasNativeImage() && modDef->GetNativeImage()->HasNativeDebugMap())
714 modDef->GetNativeImage()->GetNativeDebugMap(&count);
716 #endif // FEATURE_PREJIT
720 // Catch the exception and keep going unless COR_E_OPERATIONCANCELED
721 // was thrown. Used generating dumps, where rethrow will cancel dump.
723 EX_END_CATCH(RethrowCancelExceptions)
728 // Catch the exception and keep going unless COR_E_OPERATIONCANCELED
729 // was thrown. Used generating dumps, where rethrow will cancel dump.
731 EX_END_CATCH(RethrowCancelExceptions)
733 m_dumpStats.m_cbModuleList = m_cbMemoryReported - cbMemoryReported;
738 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
740 // Iterate through AppDomains and report specific memory needed
741 // for all dumps, such as the Module lookup path.
742 // This is intended for MiniDumpNormal and should be kept small.
744 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
745 HRESULT ClrDataAccess::EnumMemDumpAppDomainInfo(CLRDataEnumMemoryFlags flags)
749 AppDomainIterator adIter(FALSE);
752 while (adIter.Next())
754 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
756 // Note that the flags being CLRDATA_ENUM_MEM_MINI prevents
757 // you from pulling entire files loaded into memory into the dump.
758 adIter.GetDomain()->EnumMemoryRegions(flags, true);
762 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
767 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
769 // Iterating through each frame to make sure
770 // we dump out MethodDesc, DJI etc related info
771 // This is a generic helper for walking stack. However, if you call
772 // this function, make sure to flush instance in the DAC Instance manager.
774 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
775 HRESULT ClrDataAccess::EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags,
776 IXCLRDataStackWalk *pStackWalk,
781 #if defined(DAC_MEASURE_PERF)
783 unsigned __int64 nStart= GetCycleCount();
786 HRESULT status = S_OK;
787 ReleaseHolder<IXCLRDataFrame> pFrame(NULL);
788 ReleaseHolder<IXCLRDataMethodInstance> pMethod(NULL);
789 ReleaseHolder<IXCLRDataMethodDefinition> pMethodDefinition(NULL);
790 ReleaseHolder<IXCLRDataTypeInstance> pTypeInstance(NULL);
792 MethodDesc * pMethodDesc = NULL;
795 TADDR previousSP = 0; //start at zero; this allows first check to always succeed.
797 currentSP = dac_cast<TADDR>(pThread->GetCachedStackLimit()) + sizeof(TADDR);
799 // exhaust the frames using DAC api
800 bool frameHadContext;
801 for (; status == S_OK; )
803 frameHadContext = false;
804 status = pStackWalk->GetFrame(&pFrame);
805 if (status == S_OK && pFrame != NULL)
807 // write out the code that ip pointed to
810 if ((status=pFrame->GetContext(CONTEXT_ALL, sizeof(T_CONTEXT),
811 NULL, (BYTE *)&context))==S_OK)
813 // Enumerate the code around the call site to help debugger stack walking heuristics
814 ::FillRegDisplay(®Disp, &context);
815 TADDR callEnd = PCODEToPINSTR(GetControlPC(®Disp));
816 DacEnumCodeForStackwalk(callEnd);
817 frameHadContext = true;
821 // There are identical stack pointer checking semantics in code:Thread::EnumMemoryRegionsWorker
822 // See that code for comments.
823 // You ***MUST*** maintain identical semantics for both checks!
825 CLRDataSimpleFrameType simpleFrameType;
826 CLRDataDetailedFrameType detailedFrameType;
827 if (SUCCEEDED(pFrame->GetFrameType(&simpleFrameType, &detailedFrameType)))
829 if (!frameHadContext)
831 _ASSERTE(!"Stack frame should always have an associated context!");
835 // This is StackFrameIterator::SFITER_FRAMELESS_METHOD, initialized by Code:ClrDataStackWalk::GetFrame
836 // from code:ClrDataStackWalk::RawGetFrameType
837 if (simpleFrameType == CLRDATA_SIMPFRAME_MANAGED_METHOD)
839 currentSP = (TADDR)GetRegdisplaySP(®Disp);
841 if (currentSP <= previousSP)
843 _ASSERTE(!"Target stack has been corrupted, SP for current frame must be larger than previous frame.");
847 if (currentSP % sizeof(TADDR) != 0)
849 _ASSERTE(!"Target stack has been corrupted, SP must be aligned.");
853 if (!pThread->IsAddressInStack(currentSP))
855 _ASSERTE(!"Target stack has been corrupted, SP must in in the stack range.");
862 _ASSERTE(!"The stack frame should always know what type it is!");
866 status = pFrame->GetMethodInstance(&pMethod);
867 if (status == S_OK && pMethod != NULL)
870 if (SUCCEEDED(pMethod->GetTypeInstance(&pTypeInstance)) &&
871 (pTypeInstance != NULL))
873 pTypeInstance.Clear();
876 if(SUCCEEDED(pMethod->GetDefinition(&pMethodDefinition)) &&
877 (pMethodDefinition != NULL))
879 pMethodDesc = ((ClrDataMethodDefinition *)pMethodDefinition.GetValue())->GetMethodDesc();
883 // If this is a generic, we'll need to pull in enough extra info that
884 // we get decent results later when stackwalking. Note that we do not guarantee
885 // we'll always get an exact type for any reference type; most of the time the
886 // stack walk will just show System.__Canon, which is the level of support we
887 // guarantee for minidumps without full memory.
890 if ((pMethodDesc->AcquiresInstMethodTableFromThis()) ||
891 (pMethodDesc->RequiresInstMethodTableArg()))
894 ReleaseHolder<IXCLRDataValue> pDV(NULL);
895 ReleaseHolder<IXCLRDataValue> pAssociatedValue(NULL);
896 CLRDATA_ADDRESS address;
897 PTR_Object pObjThis = NULL;
899 if (SUCCEEDED(pFrame->GetArgumentByIndex(0, &pDV, 0, NULL, NULL)) &&
900 SUCCEEDED(pDV->GetAssociatedValue(&pAssociatedValue)) &&
901 SUCCEEDED(pAssociatedValue->GetAddress(&address)))
903 // Implicitly enumerate the object itself.
904 TADDR addrObjThis = CLRDATA_ADDRESS_TO_TADDR(address);
905 pObjThis = dac_cast<PTR_Object>(addrObjThis);
908 // And now get the extra info we need for the AcquiresInstMethodTableFromThis case.
909 if (pMethodDesc->AcquiresInstMethodTableFromThis())
911 // When working with the 'this' case, we need to pick up the MethodTable from
913 PTR_MethodTable pMT = NULL;
914 if (pObjThis != NULL)
916 pMT = pObjThis->GetMethodTable();
922 th = TypeHandle(pMT);
925 Instantiation classInst = pMethodDesc->GetExactClassInstantiation(th);
926 Instantiation methodInst = pMethodDesc->GetMethodInstantiation();
930 else if (pMethodDesc->RequiresInstMethodDescArg())
932 // This method has a generic type token which is required to figure out the exact instantiation
934 // We need to to use the variable index of the generic type token in order to do the look up.
935 CLRDATA_ADDRESS address = NULL;
936 DWORD dwExactGenericArgsTokenIndex = 0;
937 ReleaseHolder<IXCLRDataValue> pDV(NULL);
938 ReleaseHolder<IXCLRDataValue> pAssociatedValue(NULL);
939 ReleaseHolder<IXCLRDataFrame2> pFrame2(NULL);
941 if (SUCCEEDED(pFrame->QueryInterface(__uuidof(IXCLRDataFrame2), (void**)&pFrame2)) &&
942 SUCCEEDED(pFrame2->GetExactGenericArgsToken(&pDV)) &&
943 SUCCEEDED(pDV->GetAssociatedValue(&pAssociatedValue)) &&
944 SUCCEEDED(pAssociatedValue->GetAddress(&address)))
946 TADDR addrMD = CLRDATA_ADDRESS_TO_TADDR(address);
947 PTR_MethodDesc pMD = dac_cast<PTR_MethodDesc>(addrMD);
948 pMD->EnumMemoryRegions(flags);
951 pMethodDesc->EnumMemoryRegions(flags);
952 MethodTable * pCanonicalMT = pMethodDesc->GetCanonicalMethodTable();
953 MethodTable * pNormalMT = pMethodDesc->GetMethodTable();
954 pCanonicalMT->EnumMemoryRegions(flags);
955 pNormalMT->EnumMemoryRegions(flags);
958 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
960 pMethodDesc->EnumMemoryRegions(flags);
962 // The following calls are to ensure that mscordacwks!DacDbiInterfaceImpl::GetNativeCodeSequencePointsAndVarInfo
963 // will succeed for all dumps. Local variable info usefulness is somewhat questionable
964 // since most dumps will be for optimized targets. However, being able to map
965 // back to source lines for functions on stacks is very useful and we don't
966 // want to allow the function to fail for all targets.
968 // Pulls in sequence points and local variable info
969 DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, pMethodDesc);
971 #ifdef WIN64EXCEPTIONS
972 PCODE addr = pMethodDesc->GetNativeCode();
976 EECodeInfo codeInfo(addr);
978 // We want IsFilterFunclet to work for anything on the stack
979 codeInfo.GetJitManager()->IsFilterFunclet(&codeInfo);
981 // The stackwalker needs GC info to find the parent 'stack pointer' or PSP
982 PTR_BYTE pGCInfo = dac_cast<PTR_BYTE>(codeInfo.GetGCInfo());
985 GcInfoDecoder gcDecoder(pGCInfo, DECODE_PSP_SYM, 0);
986 DacEnumMemoryRegion(dac_cast<TADDR>(pGCInfo), gcDecoder.GetNumBytesRead(), true);
989 #endif // WIN64EXCEPTIONS
991 pMethodDefinition.Clear();
998 previousSP = currentSP;
999 status = pStackWalk->Next();
1006 // Catch the exception and keep going unless a COR_E_OPERATIONCANCELED
1007 // was thrown. In which case, rethrow to cancel the dump gathering
1009 EX_END_CATCH(RethrowCancelExceptions)
1011 #if defined(DAC_MEASURE_PERF)
1012 unsigned __int64 nEnd = GetCycleCount();
1013 g_nStackTotalTime += nEnd - nStart;
1015 #endif // #if defined(DAC_MEASURE_PERF)
1020 // code: ClrDataAccess::EnumMemDumpAllThreadsStack needs a trivial implementation of
1021 // an un-DACized container class to track what exceptions have happened so far.
1022 // It shouldn't get used anywhere else.
1023 class DebuggingExceptionTrackerList
1027 struct TrivialTADDRNode
1029 TADDR m_exceptionAddress;
1030 TrivialTADDRNode * m_pNext;
1032 TrivialTADDRNode(TrivialTADDRNode *pNext, TADDR address)
1033 : m_exceptionAddress(address), m_pNext(pNext)
1035 SUPPORTS_DAC_HOST_ONLY;
1039 TrivialTADDRNode() { _ASSERTE(!"You should never call this ctor."); }
1042 TrivialTADDRNode *m_pHead;
1044 bool Find(TADDR address)
1046 SUPPORTS_DAC_HOST_ONLY;
1047 for (TrivialTADDRNode *pFind = m_pHead; pFind != NULL; pFind = pFind->m_pNext)
1048 if (pFind->m_exceptionAddress == address)
1055 DebuggingExceptionTrackerList()
1058 SUPPORTS_DAC_HOST_ONLY;
1061 bool AddNewAddressOnly(TADDR address)
1063 SUPPORTS_DAC_HOST_ONLY;
1070 TrivialTADDRNode *pNew = new TrivialTADDRNode(m_pHead, address);
1076 ~DebuggingExceptionTrackerList()
1078 SUPPORTS_DAC_HOST_ONLY;
1079 for (TrivialTADDRNode *pTemp = m_pHead; m_pHead != NULL; pTemp = m_pHead)
1081 m_pHead = m_pHead->m_pNext;
1088 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1090 // This function will walk all threads, all the context in the
1091 // exception state to report memory. This can also drag in memory implicitly.
1093 // m_instances.DumpAllInstances(m_enumMemCb);
1094 // when function is done.
1096 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1097 HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags)
1101 #ifdef FEATURE_COMINTEROP
1102 // Dump the exception object stored in the WinRT stowed exception
1103 EnumMemStowedException(flags);
1106 HRESULT status = S_OK;
1107 TSIZE_T cbMemoryReported = m_cbMemoryReported;
1109 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1111 // Duplicate the enumeration code below, to allow Exception stacks to be enumerated first.
1112 // These exception stacks will get MethodDesc names cached to the DacStreamManager before
1113 // MethodDescs residing on the "regular" callstacks
1116 DebuggingExceptionTrackerList exceptionTrackingInner;
1118 CLRDATA_ENUM handle;
1119 ReleaseHolder<IXCLRDataTask> pIXCLRDataTask(NULL);
1120 ReleaseHolder<IXCLRDataExceptionState> pExcepState(NULL);
1121 Thread *pThread = NULL;
1123 // enumerating through each thread
1124 StartEnumTasks(&handle);
1125 status = EnumTask(&handle, &pIXCLRDataTask);
1126 for (unsigned nbThreads = 0; status == S_OK && pIXCLRDataTask != NULL; nbThreads++)
1128 // Avoid infinite loop if target process is corrupted.
1129 if (nbThreads > 100000)
1136 pThread = ((ClrDataTask *)pIXCLRDataTask.GetValue())->GetThread();
1138 // dump the exception object
1139 DumpManagedExcepObject(flags, pThread->LastThrownObject());
1141 // Now probe into the exception info
1142 status = pIXCLRDataTask->GetCurrentExceptionState(&pExcepState);
1143 while (status == S_OK && pExcepState != NULL)
1147 // touch the throwable in exception state
1148 PTR_UNCHECKED_OBJECTREF throwRef(((ClrDataExceptionState *)pExcepState.GetValue())->m_throwable);
1150 // If we've already attempted enumeration for this exception, it's time to quit.
1151 if (!exceptionTrackingInner.AddNewAddressOnly(throwRef.GetAddr()))
1156 DumpManagedExcepObject(flags, *throwRef);
1158 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1160 // get the previous exception
1161 IXCLRDataExceptionState * pExcepStatePrev = NULL;
1162 status = pExcepState->GetPrevious(&pExcepStatePrev);
1164 // Release our current exception object, and transfer ref ownership of the previous
1165 // exception object into the holder.
1166 pExcepState = pExcepStatePrev;
1169 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1172 pIXCLRDataTask.Clear();
1173 status = EnumTask(&handle, &pIXCLRDataTask);
1175 EndEnumTasks(handle);
1177 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1179 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1181 // exceptionTracking is used for exactly that; it is a per-dump list of the
1182 // addresses of all exceptions enumerated for this dump. If an exception is
1183 // enumerated more than once it indicates that we have multiple threads pointing to
1184 // the same object, or the same thread has an InnerException chain with a cycle.
1185 // In either case, we need to terminate exception reporting.
1186 DebuggingExceptionTrackerList exceptionTracking;
1190 CLRDATA_ENUM handle;
1191 ReleaseHolder<IXCLRDataTask> pIXCLRDataTask(NULL);
1192 ReleaseHolder<IXCLRDataExceptionState> pExcepState(NULL);
1193 ReleaseHolder<IXCLRDataStackWalk> pStackWalk(NULL);
1194 Thread *pThread = NULL;
1196 // enumerating through each thread's each frame, dump out some interesting
1197 // code memory needed to debugger to recognize frame
1199 ThreadStore::EnumMemoryRegions(flags);
1201 // enumerating through each thread
1202 StartEnumTasks(&handle);
1203 status = EnumTask(&handle, &pIXCLRDataTask);
1204 for (unsigned nbThreads = 0; status == S_OK && pIXCLRDataTask != NULL; nbThreads++)
1206 // Avoid infinite loop if target process is corrupted.
1207 if (nbThreads > 100000)
1214 pThread = ((ClrDataTask *)pIXCLRDataTask.GetValue())->GetThread();
1216 // Write out the Thread instance
1217 DacEnumHostDPtrMem(pThread);
1219 // Write out the context pointed by the thread
1220 DacEnumHostDPtrMem(pThread->GetContext());
1223 // write TEB pointed by the thread
1224 // DacEnumHostDPtrMem(pThread->GetTEB());
1227 // If CLR is hosted, we want to write out fiber data
1229 // Dump the managed thread object
1230 DumpManagedObject(flags, pThread->GetExposedObjectRaw());
1232 #ifndef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1233 // dump the exception object
1234 DumpManagedExcepObject(flags, pThread->LastThrownObject());
1235 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1238 // We need for the ClrDataTask::CreateStackWalk from IXCLRDataTask to work, which is the
1239 // following walk. However, the CordbStackWalk code requires some different (extra) data
1240 // to walk the stack, such as info being present for
1241 // mscordacwks!DacDbiInterfaceImpl::GetNativeCodeSequencePointsAndVarInfo.
1242 status = pIXCLRDataTask->CreateStackWalk(CLRDATA_SIMPFRAME_UNRECOGNIZED | CLRDATA_SIMPFRAME_MANAGED_METHOD | CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE | CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE,
1244 if (status == S_OK && pStackWalk != NULL)
1246 status = EnumMemWalkStackHelper(flags, pStackWalk, pThread);
1250 // Now probe into the exception info
1251 status = pIXCLRDataTask->GetCurrentExceptionState(&pExcepState);
1252 while (status == S_OK && pExcepState != NULL)
1256 // touch the throwable in exception state
1257 PTR_UNCHECKED_OBJECTREF throwRef(((ClrDataExceptionState *)pExcepState.GetValue())->m_throwable);
1259 // If we've already attempted enumeration for this exception, it's time to quit.
1260 if (!exceptionTracking.AddNewAddressOnly(throwRef.GetAddr()))
1265 #ifndef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1266 DumpManagedExcepObject(flags, *throwRef);
1267 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1269 // get the type of the exception
1270 ReleaseHolder<IXCLRDataValue> pValue(NULL);
1271 status = pExcepState->GetManagedObject(&pValue);
1272 if (status == S_OK && pValue != NULL)
1274 ReleaseHolder<IXCLRDataTypeInstance> pTypeInstance(NULL);
1275 // Make sure that we can get back a TypeInstance during inspection
1276 status = pValue->GetType(&pTypeInstance);
1280 // If Exception state has a new context, we will walk with the stashed context as well.
1281 // Note that in stack overflow exception's case, m_pContext is null.
1283 // It is possible that we are in exception's catch clause when we
1284 // try to walk the stack below. This is a very weird situation where
1285 // stack is logically unwind and not physically unwind. We may not be able
1286 // to walk the stack correctly here. Anyway, we try to catch exception thrown
1287 // by bad stack walk in EnumMemWalkStackHelper.
1289 PTR_CONTEXT pContext = ((ClrDataExceptionState*)pExcepState.GetValue())->GetCurrentContextRecord();
1290 if (pContext != NULL)
1292 T_CONTEXT newContext;
1293 newContext = *pContext;
1295 // We need to trigger stack walk again using the exception's context!
1296 status = pIXCLRDataTask->CreateStackWalk(CLRDATA_SIMPFRAME_UNRECOGNIZED | CLRDATA_SIMPFRAME_MANAGED_METHOD | CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE | CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE,
1298 if (status == S_OK && pStackWalk != NULL)
1300 status = pStackWalk->SetContext2(CLRDATA_STACK_SET_CURRENT_CONTEXT, sizeof(T_CONTEXT), (BYTE *) &newContext);
1303 status = EnumMemWalkStackHelper(flags, pStackWalk, pThread);
1309 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1311 // get the previous exception
1312 IXCLRDataExceptionState * pExcepStatePrev = NULL;
1313 status = pExcepState->GetPrevious(&pExcepStatePrev);
1315 // Release our current exception object, and transfer ref ownership of the previous
1316 // exception object into the holder.
1317 pExcepState = pExcepStatePrev;
1320 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1323 pIXCLRDataTask.Clear();
1324 status = EnumTask(&handle, &pIXCLRDataTask);
1326 EndEnumTasks(handle);
1328 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1330 // updating the statistics
1331 m_dumpStats.m_cbStack = m_cbMemoryReported - cbMemoryReported;
1337 #ifdef FEATURE_COMINTEROP
1338 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1340 // WinRT stowed exception holds the (CCW)pointer to a managed exception object.
1341 // We should check for the presence of a such an exception object and dump it if available.
1342 // This can also drag in memory implicitly.
1344 // m_instances.DumpAllInstances(m_enumMemCb);
1345 // when function is done.
1347 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1348 HRESULT ClrDataAccess::EnumMemStowedException(CLRDataEnumMemoryFlags flags)
1352 ICLRDataTarget3 *pTarget3 = GetLegacyTarget3();
1353 if (pTarget3 == NULL)
1356 // get the thread that raised the exception
1357 ULONG32 exThreadID = 0;
1358 if (FAILED(pTarget3->GetExceptionThreadID(&exThreadID)) || exThreadID == 0)
1362 // check that the thread is one of the known managed threads
1364 BOOL foundThread = FALSE;
1365 CLRDATA_ENUM handle;
1366 ReleaseHolder<IXCLRDataTask> pIXCLRDataTask(NULL);
1368 // enumerate through each thread
1369 StartEnumTasks(&handle);
1370 HRESULT status = EnumTask(&handle, &pIXCLRDataTask);
1371 for (unsigned nbThreads = 0; status == S_OK && pIXCLRDataTask != NULL; ++nbThreads)
1373 // Avoid infinite loop if target process is corrupted.
1374 if (nbThreads > 100000)
1380 if (((ClrDataTask *)pIXCLRDataTask.GetValue())->GetThread()->GetOSThreadId() == exThreadID)
1387 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1390 pIXCLRDataTask.Clear();
1391 status = EnumTask(&handle, &pIXCLRDataTask);
1393 EndEnumTasks(handle);
1400 // Read the remote stowed exceptions.
1402 // EXCEPTION_RECORD.ExceptionCode: STATUS_STOWED_EXCEPTION.
1403 // EXCEPTION_RECORD.NumberParameters: 2.
1404 // EXCEPTION_RECORD.ExceptionInformation[0]: pointer to an array of pointers
1405 // to STOWED_EXCEPTION_INFORMATION structures.
1406 // EXCEPTION_RECORD.ExceptionInformation[1]: count of elements in the array.
1408 ULONG32 bytesRead = 0;
1409 MINIDUMP_EXCEPTION minidumpException = { 0 };
1410 if (FAILED(pTarget3->GetExceptionRecord(sizeof(MINIDUMP_EXCEPTION), &bytesRead, (PBYTE)&minidumpException)))
1413 TADDR remoteStowedExceptionArray = (TADDR)minidumpException.ExceptionInformation[0];
1414 ULONG stowedExceptionCount = (ULONG)minidumpException.ExceptionInformation[1];
1415 if (bytesRead != sizeof(MINIDUMP_EXCEPTION)
1416 || minidumpException.ExceptionCode != STATUS_STOWED_EXCEPTION
1417 || minidumpException.NumberParameters != 2
1418 || stowedExceptionCount < 1 // there must atleast be 1 stowed exception
1419 || stowedExceptionCount > 256 // upper bound: 256
1420 || remoteStowedExceptionArray == NULL)
1425 for (ULONG i = 0; i < stowedExceptionCount; ++i)
1427 // Read the i-th stowed exception
1428 TADDR remoteStowedException = NULL;
1429 if (FAILED(m_pTarget->ReadVirtual(TO_CDADDR(remoteStowedExceptionArray + (i * sizeof(TADDR))),
1430 (PBYTE)&remoteStowedException, sizeof(TADDR), &bytesRead))
1431 || bytesRead != sizeof(TADDR)
1432 || remoteStowedException == NULL)
1437 // check if this is a v2 stowed exception
1438 STOWED_EXCEPTION_INFORMATION_V2 stowedException = { 0 };
1439 if (FAILED(m_pTarget->ReadVirtual(TO_CDADDR(remoteStowedException),
1440 (PBYTE)&stowedException, sizeof(STOWED_EXCEPTION_INFORMATION_HEADER), &bytesRead))
1441 || bytesRead != sizeof(STOWED_EXCEPTION_INFORMATION_HEADER)
1442 || stowedException.Header.Signature != STOWED_EXCEPTION_INFORMATION_V2_SIGNATURE)
1447 // Read the full v2 stowed exception and get the CCW pointer out of it
1448 if (FAILED(m_pTarget->ReadVirtual(TO_CDADDR(remoteStowedException),
1449 (PBYTE)&stowedException, sizeof(STOWED_EXCEPTION_INFORMATION_V2), &bytesRead))
1450 || bytesRead != sizeof(STOWED_EXCEPTION_INFORMATION_V2)
1451 || stowedException.NestedExceptionType != STOWED_EXCEPTION_NESTED_TYPE_LEO
1452 || stowedException.NestedException == NULL)
1457 // Find out if NestedException is a pointer to CCW and then dump the exception object in it
1458 DumpStowedExceptionObject(flags, TO_CDADDR(stowedException.NestedException));
1464 HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, CLRDATA_ADDRESS ccwPtr)
1470 // dump the managed exception object wrapped in CCW
1471 // memory of the CCW object itself is dumped later by DacInstanceManager::DumpAllInstances
1472 DacpCCWData ccwData;
1473 GetCCWData(ccwPtr, &ccwData); // this call collects some memory implicitly
1474 DumpManagedExcepObject(flags, OBJECTREF(TO_TADDR(ccwData.managedObject)));
1476 // dump memory of the 2nd slot in the CCW's vtable
1477 // this is used in DACGetCCWFromAddress to identify if the passed in pointer is a valid CCW.
1478 ULONG32 bytesRead = 0;
1479 TADDR vTableAddress = NULL;
1480 if (FAILED(m_pTarget->ReadVirtual(ccwPtr, (PBYTE)&vTableAddress, sizeof(TADDR), &bytesRead))
1481 || bytesRead != sizeof (TADDR)
1482 || vTableAddress == NULL)
1487 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
1489 ReportMem(vTableAddress + sizeof(PBYTE)* TEAR_OFF_SLOT, sizeof(TADDR));
1496 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
1497 #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
1499 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1501 // Reports critical data from the CLR main module
1502 // that needs to be present in all minidumps.
1503 // Implicitly reports memory, so remember to call
1504 // m_instances.DumpAllInstances(m_enumMemCb);
1505 // after this function completes.
1507 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1508 HRESULT ClrDataAccess::EnumMemCLRMainModuleInfo()
1512 HRESULT status = S_OK;
1514 // PEDecoder is DACized, so we just need to touch what we want to
1515 // make subsequent lookup work.
1516 PEDecoder pe(m_globalBase);
1518 // We currently only actually have one debug directory entry.
1519 // Post-processing, such as optimization, may add an extra directory.
1520 // These directories are of type IMAGE_DEBUG_TYPE_RESERVED10, while our
1521 // standard CodeView directory with pdb info is IMAGE_DEBUG_TYPE_CODEVIEW.
1523 for (i = 0; pe.GetDebugDirectoryEntry(i); i++)
1529 status = E_UNEXPECTED;
1530 _ASSERTE(!"Collecting dump of target with no debug directory entries!");
1533 // For CLRv4+, the resource directory contains the necessary info
1534 // to retrieve the DBI/DAC from a symbol server.
1535 // Specifically, in v4 it contains a mscoree!PE_FIXEDFILEINFO.
1536 // This is also required since OpenVirtualProcess will check against
1537 // this content to determine if a target module is indeed a CLR
1540 // Retrieve all resources in clr.dll. Right now, the entire resource
1541 // content is very small (~0x600 bytes of raw data), so getting all is
1542 // the easy thing to do. If resources become larger in later
1543 // releases, we'll have to specifically get just the debugging-related resources.
1544 _ASSERTE(pe.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE));
1545 if (pe.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
1548 TADDR pResourceDirData = pe.GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_RESOURCE, &size);
1550 _ASSERTE(size < 0x2000);
1551 ReportMem((TADDR)pResourceDirData, size, true);
1555 // In later releases, we should log the ERROR_RESOURCE_DATA_NOT_FOUND.
1556 status = E_UNEXPECTED;
1563 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1565 // Generating skinny mini-dump. Skinny mini-dump will only support stack trace, module list,
1566 // and Exception list viewing.
1568 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1569 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerSkinny(IN CLRDataEnumMemoryFlags flags)
1573 HRESULT status = S_OK;
1575 // clear all of the previous cached memory
1578 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1579 // Enable caching enumerated metadata of interest
1580 InitStreamsForWriting(flags);
1581 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1583 //TODO: actually *do* something with potential failures. It would be relatively easy to
1584 // hook up an official dump stream to put info on our failures and other 'metadata'
1585 // about dumping into in a generic sort of way. Our code doesn't have access to
1586 // MDWD's callbacks, so we can't just do it ourselves. Thus we could have useful info
1587 // baked into the dump, like we failed to enumerate mem for certain threads, etc.
1589 // Each enumeration function below should be wrapped in a try/catch
1590 // so that we have a chance to create a debuggable dump in the face of target problems.
1592 // Iterating to all threads' stacks
1593 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(flags); )
1595 // Iterating to module list.
1596 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(flags); )
1599 // iterating through static that we care
1601 // collect CLR static
1602 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(flags); )
1604 // now dump the memory get dragged in by using DAC API implicitly.
1605 m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
1606 status = m_memStatus;
1608 // Dump AppDomain-specific info needed for MiniDumpNormal.
1609 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAppDomainInfo(flags); )
1611 // Dump the Debugger object data needed
1612 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugger->EnumMemoryRegions(flags); )
1614 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1615 // Dump the extra data needed for metadata-free debugging
1616 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( EnumStreams(flags); )
1617 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1619 // Do not let any remaining implicitly enumerated memory leak out.
1625 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1627 // Generating triage micro-dump. Triage dumps will only support stack trace
1628 // and Exception viewing.More than that triage dumps have to be PII free,
1629 // so all exception messages have to be poisoned with 0xcc mask.
1631 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1632 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerMicroTriage(IN CLRDataEnumMemoryFlags flags)
1636 HRESULT status = S_OK;
1638 // clear all of the previous cached memory
1641 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1642 // Enable caching enumerated metadata of interest
1643 InitStreamsForWriting(flags);
1644 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1646 // Iterating to all threads' stacks
1647 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(flags); )
1649 // Iterating to module list.
1650 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(flags); )
1652 // collect CLR static
1653 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(flags); )
1655 // now dump the memory get dragged in by using DAC API implicitly.
1656 m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
1657 status = m_memStatus;
1659 // Dump AppDomain-specific info needed for triage dumps methods enumeration (k command).
1660 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAppDomainInfo(flags); )
1662 // Dump the Debugger object data needed
1663 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugger->EnumMemoryRegions(flags); )
1665 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1666 // Dump the extra data needed for metadata-free debugging
1667 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( EnumStreams(flags); )
1668 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1670 // Do not let any remaining implicitly enumerated memory leak out.
1676 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1678 // Write out mscorwks's data segment. This will write out the whole
1679 // data segment for mscorwks. It is about 200 or 300K. Most of it (90%) are
1680 // vtable definition that we don't really care. But we don't have a
1681 // good walk to just write out all globals and statics.
1683 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1684 HRESULT ClrDataAccess::EnumMemWriteDataSegment()
1688 NewHolder<PEDecoder> pedecoder(NULL);
1692 // Collecting mscorwks's data segment
1694 // m_globalBase is the base address of target process's mscorwks module
1695 pedecoder = new PEDecoder(dac_cast<PTR_VOID>(m_globalBase));
1697 PTR_IMAGE_SECTION_HEADER pSection = (PTR_IMAGE_SECTION_HEADER) pedecoder->FindFirstSection();
1698 PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(pedecoder->GetNumberOfSections());
1700 while (pSection < pSectionEnd)
1702 if (pSection->Name[0] == '.' &&
1703 pSection->Name[1] == 'd' &&
1704 pSection->Name[2] == 'a' &&
1705 pSection->Name[3] == 't' &&
1706 pSection->Name[4] == 'a')
1708 // This is the .data section of mscorwks
1709 ReportMem(m_globalBase + pSection->VirtualAddress, pSection->Misc.VirtualSize);
1715 EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1720 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1722 // Custom Dump. Depending on the value of g_ECustomDumpFlavor, different dump
1723 // will be taken. You can set this global variable using hosting API
1724 // ICLRErrorReportingManager::BeginCustomDump.
1726 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1727 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerCustom()
1731 HRESULT status = S_OK;
1733 ECustomDumpFlavor eFlavor;
1735 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
1736 eFlavor = CCLRErrorReportingManager::g_ECustomDumpFlavor;
1738 eFlavor = DUMP_FLAVOR_Default;
1741 m_enumMemFlags = CLRDATA_ENUM_MEM_MINI;
1743 // clear all of the previous cached memory
1746 if (eFlavor == DUMP_FLAVOR_Mini)
1748 // Iterating to all threads' stacks
1749 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(m_enumMemFlags); )
1751 // Iterating to module list.
1752 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(m_enumMemFlags); )
1755 // iterating through static that we care
1757 // collect CLR static
1758 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); )
1762 // now dump the memory get dragged in implicitly
1763 m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
1766 else if (eFlavor == DUMP_FLAVOR_CriticalCLRState)
1768 // We need to walk Threads stack to view managed frames.
1769 // Iterating through module list
1771 // Iterating to all threads' stacks
1772 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(m_enumMemFlags); )
1774 // Iterating to module list.
1775 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(m_enumMemFlags); )
1778 // iterating through static that we care
1780 // collect CLR static
1781 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); )
1783 // Collecting some CLR secondary critical data
1784 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRHeapCrticalStatic(m_enumMemFlags); )
1785 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemWriteDataSegment(); )
1789 // now dump the memory get dragged in implicitly
1790 m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
1793 else if (eFlavor == DUMP_FLAVOR_NonHeapCLRState)
1795 // since all CLR hosted heap will be dump by the host,
1796 // the EE structures that are not loaded using LoadLibrary will
1797 // be included by the host.
1799 // Thus we only need to include mscorwks's critical data and ngen images
1801 m_enumMemFlags = CLRDATA_ENUM_MEM_HEAP;
1803 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); )
1805 // Collecting some CLR secondary critical data
1806 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRHeapCrticalStatic(m_enumMemFlags); )
1808 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemWriteDataSegment(); )
1809 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCollectImages(); )
1813 status = E_INVALIDARG;
1816 status = m_memStatus;
1821 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1823 // Minidumps traverse a giant static calltree. We already try to catch
1824 // exceptions at various lower level places and continue to report memory.
1826 // However, if we'll jump to the top-level catcher and skip the rest of the tree,
1827 // that may mean some key data may not get emitted to the minidump.
1828 // In the case that a user requests a dump is canceled, we should skip the rest
1829 // of the tree. When a COR_E_OPERATIONCANCELED exception is thrown, is allowed to
1830 // escape all the way to this function. If any exception makes it here and is not
1831 // COR_E_OPERATIONCANCELED that indicates an issue, and the assert is meant to catch that.
1832 // Unfortunately the stack unwind will already have happened.
1834 // Internal API to support minidump and heap dump. It just delegate
1835 // to proper function but with a top level catch.
1837 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1838 HRESULT ClrDataAccess::EnumMemoryRegionsWrapper(IN CLRDataEnumMemoryFlags flags)
1840 // This is infrastructure code - we don't want DacCop complaining about the calls as a result
1841 // of the use of EX_CATCH_HRESULT here. We're careful to mark EnumMemoryRegionsWorkerSkinny
1842 // and EnumMemoryRegionsWorkerHeap as just SUPPORTS_DAC so that we still get analysis.
1843 SUPPORTS_DAC_HOST_ONLY;
1845 HRESULT status = S_OK;
1846 m_enumMemFlags = flags;
1849 // The various EnumMemoryRegions() implementations should understand
1850 // CLRDATA_ENUM_MEM_MINI to mean that the bare minimimum memory
1851 // to make a MiniDumpNormal work should be included.
1852 if ( flags == CLRDATA_ENUM_MEM_MINI)
1855 status = EnumMemoryRegionsWorkerSkinny(flags);
1857 else if ( flags == CLRDATA_ENUM_MEM_TRIAGE)
1859 // triage micro-dump
1860 status = EnumMemoryRegionsWorkerMicroTriage(flags);
1862 else if ( flags == CLRDATA_ENUM_MEM_HEAP)
1864 status = EnumMemoryRegionsWorkerHeap(flags);
1868 _ASSERTE(!"Bad flags passing to EnumMemoryRegionsWrapper!");
1871 EX_CATCH_HRESULT(status);
1873 // The only exception that should reach here is the cancel exception
1874 _ASSERTE(SUCCEEDED(status) || status == COR_E_OPERATIONCANCELED);
1879 #define MiniDumpWithPrivateReadWriteMemory 0x00000200
1880 #define MiniDumpWithFullAuxiliaryState 0x00008000
1881 #define MiniDumpFilterTriage 0x00100000
1885 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1887 // Entry function for generating CLR aware dump. This function is called
1888 // for minidump, heap dump, and custom dumps. CLR specific memory will
1889 // be reported to outer level dumper (usually dbghelp's MiniDumpWriteDump api)
1890 // through the callback. We do not write out to file directly.
1892 // N.B.: The CLR may report duplicate memory chunks and it's up to
1893 // the debugger to coalesce memory. *However* the debugger's current
1894 // implementation coalesces memory we enumerate and memory that
1895 // they enumerate; the two sets of memory are not guaranteed to be
1896 // coalesced. The dump produced may thus have memory blocks in the
1897 // MemoryListStream that overlap or are totally contained in other blocks.
1898 // This issue was resolved by-design by dbgteam. Win7 #407019.
1899 // Note also that Memory64ListStream (when passing MiniDumpWithFullMemory)
1900 // will have no duplicates, be sorted, etc. In that case, none of
1901 // our code is called.
1903 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1905 ClrDataAccess::EnumMemoryRegions(IN ICLRDataEnumMemoryRegionsCallback* callback,
1906 IN ULONG32 miniDumpFlags,
1907 IN CLRDataEnumMemoryFlags flags) // reserved not used
1912 #if defined(DAC_MEASURE_PERF)
1915 g_nStackTotalTime = 0;
1916 g_nReadVirtualTotalTime = 0;
1917 g_nFindTotalTime = 0;
1918 g_nFindHashTotalTime = 0;
1923 g_nFindStackTotalTime = 0;
1925 LARGE_INTEGER nClockFrequency;
1926 unsigned __int64 nStart = 0;
1927 unsigned __int64 nEnd = 0;
1929 QueryPerformanceFrequency(&nClockFrequency);
1931 FILE* fp = fopen("c:\\dumpLog.txt", "a");
1934 fprintf(fp, "\nMinidumpFlags = %d\n", miniDumpFlags);
1938 nStart = GetCycleCount();
1940 #endif // #if defined(DAC_MEASURE_PERF)
1944 // We should not be trying to enumerate while we have an enumeration outstanding
1945 _ASSERTE(m_enumMemCb==NULL);
1947 m_enumMemCb = callback;
1949 // QI for ICLRDataEnumMemoryRegionsCallback2 will succeed only for Win8+.
1950 // It is expected to fail on pre Win8 OSes.
1951 callback->QueryInterface(IID_ICLRDataEnumMemoryRegionsCallback2, (void **)&m_updateMemCb);
1956 if (miniDumpFlags & MiniDumpWithPrivateReadWriteMemory)
1959 status = EnumMemoryRegionsWrapper(CLRDATA_ENUM_MEM_HEAP);
1961 else if (miniDumpFlags & MiniDumpWithFullAuxiliaryState)
1963 // This is the host custom dump.
1964 status = EnumMemoryRegionsWorkerCustom();
1966 else if (miniDumpFlags & MiniDumpFilterTriage)
1968 // triage micro-dump
1969 status = EnumMemoryRegionsWrapper(CLRDATA_ENUM_MEM_TRIAGE);
1974 status = EnumMemoryRegionsWrapper(CLRDATA_ENUM_MEM_MINI);
1977 // For all dump types, we need to capture the chain to the IMAGE_DIRECTORY_ENTRY_DEBUG
1978 // contents, so that DAC can validate against the TimeDateStamp even if the
1979 // debugger can't find the main CLR module on disk.
1980 // If we already failed, don't bother.
1981 if (SUCCEEDED(status))
1983 // In case there's implicitly enumerated memory hanging around
1984 // let's not accidentally pick it up.
1986 if (SUCCEEDED(status = EnumMemCLRMainModuleInfo()))
1988 m_instances.DumpAllInstances(m_enumMemCb);
1998 // We should never actually be here b/c none of the EMR functions should throw.
1999 // They should all either be written robustly w/ ptr.IsValid() and catching their
2001 if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
2003 _ASSERTE_MSG(false, "Got unexpected exception in EnumMemoryRegions");
2007 EX_END_CATCH(SwallowAllExceptions)
2009 // fix for issue 866100: DAC is too late in releasing ICLRDataEnumMemoryRegionsCallback2*
2012 m_updateMemCb->Release();
2013 m_updateMemCb = NULL;
2019 #if defined(DAC_MEASURE_PERF)
2021 nEnd = GetCycleCount();
2022 g_nTotalTime= nEnd - nStart;
2023 fp = fopen("c:\\dumpLog.txt", "a");
2024 fprintf(fp, "Total = %g msec\n"
2025 "ReadVirtual = %g msec\n"
2026 "StackWalk = %g msec; Find: %g msec\n"
2027 "Find = %g msec; Hash = %g msec; Calls = %I64u; Hits = %I64u; Not found = %I64u\n\n=====\n",
2028 (float) (1000*g_nTotalTime/nClockFrequency.QuadPart),
2029 (float) (1000*g_nReadVirtualTotalTime/nClockFrequency.QuadPart),
2030 (float) (1000*g_nStackTotalTime/nClockFrequency.QuadPart), (float) (1000*g_nFindStackTotalTime/nClockFrequency.QuadPart),
2031 (float) (1000*g_nFindTotalTime/nClockFrequency.QuadPart), (float) (1000*g_nFindHashTotalTime/nClockFrequency.QuadPart),
2032 g_nFindCalls, g_nFindHits, g_nFindFails
2036 #endif // #if defined(DAC_MEASURE_PERF)
2042 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2044 // Clear the statistics for the dump. For each dump generation, we
2045 // clear the dump statistics. At the end of the dump generation, you can
2046 // view the statics data member m_dumpStats and see how many bytes that
2047 // we have reported to our debugger host.
2049 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2050 void ClrDataAccess::ClearDumpStats()
2054 m_cbMemoryReported = 0;
2055 memset(&m_dumpStats, 0, sizeof(DumpMemoryReportStatics));