Add a fourth parameter to the DEFINE_DACVAR macro that is the actual fully qualified...
[platform/upstream/coreclr.git] / src / debug / daccess / enummem.cpp
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 //*****************************************************************************
6 // File: enummem.cpp
7 // 
8
9 //
10 // ICLRDataEnumMemoryRegions implementation.
11 //
12 //*****************************************************************************
13
14 #include "stdafx.h"
15
16 #include <eeconfig.h>
17 #include <ecall.h>
18 #include <gcinfodecoder.h>
19
20 #include "typestring.h"
21 #include "daccess.h"
22 #include "ipcmanagerinterface.h"
23 #include "binder.h"
24 #include "win32threadpool.h"
25 #include "gcscan.h"
26
27 #ifdef FEATURE_APPX
28 #include "appxutil.h"
29 #endif // FEATURE_APPX
30
31 #if defined(DAC_MEASURE_PERF)
32
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;
43
44 #endif // #if defined(DAC_MEASURE_PERF)
45
46
47 //
48 // EnumMemCollectImages - collect all images of interest for heap dumps
49 //
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.
59 //
60 // We also currently include in-memory modules (provided by a host, or loaded
61 // from a Byte[]).
62 //
63 HRESULT ClrDataAccess::EnumMemCollectImages()
64 {
65     SUPPORTS_DAC;
66
67     ProcessModIter modIter;
68     Module* modDef = NULL;
69     HRESULT status = S_OK;
70     PEFile  *file;
71     TADDR pStartAddr = 0;
72     ULONG32 ulSize = 0;
73     ULONG32 ulSizeBlock;
74
75     TSIZE_T cbMemoryReported = m_cbMemoryReported;
76
77     //
78     // Collect the ngen images - Iterating through module list
79     //
80     EX_TRY
81     {
82         while ((modDef = modIter.NextModule()))
83         {
84             EX_TRY
85             {
86                 ulSize = 0;
87                 file = modDef->GetFile();
88
89                 // We want to save all native images
90                 if (file->HasNativeImage())
91                 {
92                     // We should only skip if signed by Microsoft!
93                     pStartAddr = PTR_TO_TADDR(file->GetLoadedNative()->GetBase());
94                     ulSize = file->GetLoadedNative()->GetSize();
95                 }
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.
101                 else
102                 if (
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)
112                 {
113                     pStartAddr = PTR_TO_TADDR(file->GetLoadedIL()->GetBase());
114                     ulSize = file->GetLoadedIL()->GetSize();
115                 }
116
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
120                 //
121                 while (ulSize > 0)
122                 {
123                     //
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.
129                     //
130                     ulSizeBlock = ulSize > OS_PAGE_SIZE ? OS_PAGE_SIZE : ulSize;
131                     ReportMem(pStartAddr, ulSizeBlock, false);
132                     pStartAddr += ulSizeBlock;
133                     ulSize -= ulSizeBlock;
134                 }
135             }
136             EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
137         }
138     }
139     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
140
141     m_dumpStats.m_cbNgen = m_cbMemoryReported - cbMemoryReported;
142     return status;
143 }
144
145
146
147 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
148 //
149 // collecting memory for mscorwks's heap dump critical statics
150 // This include the stress log, config structure, and IPC block
151 //
152 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
153 HRESULT ClrDataAccess::EnumMemCLRHeapCrticalStatic(IN CLRDataEnumMemoryFlags flags)
154 {
155     SUPPORTS_DAC;
156
157     TSIZE_T cbMemoryReported = m_cbMemoryReported;
158
159     // Write out the stress log structure itself
160     DacEnumHostDPtrMem(g_pStressLog);
161
162     // This is pointing to a static buffer
163     DacEnumHostDPtrMem(g_pConfig);
164
165     // dump GC heap structures. Note that the managed heap is not dumped out. 
166     // We are just dump the GC heap structures.
167     //
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); );
171 #endif
172
173 #ifdef FEATURE_IPCMAN
174     //
175     // Write Out IPC Blocks
176     //
177     EX_TRY
178     {
179         g_pIPCManagerInterface.EnumMem();
180         if (g_pIPCManagerInterface.IsValid())
181         {
182             // write out the instance
183             DacEnumHostDPtrMem(g_pIPCManagerInterface);
184
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());
188         }
189     }
190     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
191 #endif // FEATURE_IPCMAN
192
193     m_dumpStats.m_cbClrHeapStatics = m_cbMemoryReported - cbMemoryReported;
194
195     return S_OK;
196 }
197
198 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
199 //
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
202 // to work. 
203 //
204 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
205 HRESULT ClrDataAccess::EnumMemCLRStatic(IN CLRDataEnumMemoryFlags flags)
206 {
207     SUPPORTS_DAC;
208
209     TSIZE_T cbMemoryReported = m_cbMemoryReported;
210
211     //
212     // write out the static and global content that we care.
213     //
214
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 
217     // global pointers.
218     //
219 #define DEFINE_DACVAR(id_type, size_type, id, var) \
220     ReportMem(m_globalBase + g_dacGlobals.id, sizeof(size_type));
221
222 #define DEFINE_DACVAR_SVR(id_type, size_type, id, var) \
223     ReportMem(m_globalBase + g_dacGlobals.id, sizeof(size_type));
224
225     // Cannot use CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
226     // around conditional preprocessor directives in a sane fashion.
227     EX_TRY
228     {
229 #include "dacvars.h"
230     }
231     EX_CATCH
232     {
233         // Catch the exception and keep going unless COR_E_OPERATIONCANCELED
234         // was thrown. Used generating dumps, where rethrow will cancel dump.
235     }
236     EX_END_CATCH(RethrowCancelExceptions)
237
238     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
239     (
240         // StressLog is not defined on Rotor build for DAC
241         ReportMem(m_globalBase + g_dacGlobals.dac__g_pStressLog, sizeof(StressLog *));
242     );
243
244     EX_TRY
245     {
246         // These two static pointers are pointed to static data of byte[]
247         // then run constructor in place
248         //
249         ReportMem(m_globalBase + g_dacGlobals.SystemDomain__m_pSystemDomain,
250                   sizeof(SystemDomain));
251         ReportMem(m_globalBase + g_dacGlobals.SharedDomain__m_pSharedDomain,
252                   sizeof(SharedDomain));
253
254         // We need GCHeap pointer to make EEVersion work
255         ReportMem(m_globalBase + g_dacGlobals.dac__g_pGCHeap,
256               sizeof(GCHeap *));
257
258         // see synblk.cpp, the pointer is pointed to a static byte[]
259         SyncBlockCache::s_pSyncBlockCache.EnumMem();
260
261 #ifndef FEATURE_IMPLICIT_TLS
262         ReportMem(m_globalBase + g_dacGlobals.dac__gThreadTLSIndex,
263                   sizeof(DWORD));
264         ReportMem(m_globalBase + g_dacGlobals.dac__gAppDomainTLSIndex,
265                   sizeof(DWORD));
266 #endif
267
268         ReportMem( m_globalBase + g_dacGlobals.dac__g_FCDynamicallyAssignedImplementations,
269                   sizeof(TADDR)*ECall::NUM_DYNAMICALLY_ASSIGNED_FCALL_IMPLEMENTATIONS);
270     }
271     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
272
273 #ifndef FEATURE_PAL
274     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_runtimeLoadedBaseAddress.EnumMem(); )
275 #endif // !FEATURE_PAL
276
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.
280         //
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(); )
300
301         // These two static pointers are pointed to static data of byte[]
302         // then run constructor in place
303         //
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(); )
316     
317 #ifdef FEATURE_SVR_GC
318     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
319     (
320         GCHeap::gcHeapType.EnumMem();
321     );
322 #endif // FEATURE_SVR_GC
323
324     m_dumpStats.m_cbClrStatics = m_cbMemoryReported - cbMemoryReported;
325
326     return S_OK;
327 }
328
329 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
330 //
331 // This function reports memory that a heap dump need to debug CLR
332 // and managed code efficiently.
333 //
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....
339 //
340 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
341 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerHeap(IN CLRDataEnumMemoryFlags flags)
342 {
343     SUPPORTS_DAC;
344
345     HRESULT status = S_OK;
346
347     m_instances.ClearEnumMemMarker();
348
349     // clear all of the previous cached memory
350     Flush();
351
352     // collect ngen image
353     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCollectImages(); );
354
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); );
358
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
362     //
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); );
366
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); )
370
371     // Dump AppDomain-specific info 
372     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAppDomainInfo(flags); )
373
374     // Dump the Debugger object data needed
375     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugger->EnumMemoryRegions(flags); )
376
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
380
381     // end of code
382     status = m_memStatus;
383
384     return S_OK;
385 }   // EnumMemoryRegionsWorkerHeap
386
387 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
388 //
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
392 //
393 //
394 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
395 HRESULT ClrDataAccess::DumpManagedObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef)
396 {
397     SUPPORTS_DAC;
398
399     HRESULT     status = S_OK;
400
401     if (objRef == NULL)
402     {
403         return status;
404     }
405     
406     if (!CNameSpace::GetGcRuntimeStructuresValid ())
407     {
408         // GC is in progress, don't dump this object
409         return S_OK;
410     }
411     
412     EX_TRY
413     {
414         // write out the current EE class and the direct/indirect inherited EE Classes        
415         MethodTable *pMethodTable = objRef->GetGCSafeMethodTable();
416
417         while (pMethodTable)
418         {
419             EX_TRY
420             {
421                 pMethodTable->EnumMemoryRegions(flags);
422
423                 StackSString s;
424                 
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
428                 // memory. 
429                 // 
430                 TypeString::AppendType(s, TypeHandle(pMethodTable), TypeString::FormatNamespace|TypeString::FormatFullInst);
431             }
432             EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
433
434             // Walk up to parent MethodTable
435             pMethodTable = pMethodTable->GetParentMethodTable();
436         }
437
438         // now dump the content for the managed object
439         objRef->EnumMemoryRegions();
440     }
441     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
442
443     return status;
444 }
445
446
447 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
448 //
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,
452 // inner exception.
453 //
454 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
455 HRESULT ClrDataAccess::DumpManagedExcepObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef)
456 {
457     SUPPORTS_DAC;
458
459     if (objRef == NULL)
460     {
461         return S_OK;
462     }
463
464     if (!CNameSpace::GetGcRuntimeStructuresValid ())
465     {
466         // GC is in progress, don't dump this object
467         return S_OK;
468     }
469
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
473     // the fields. 
474     //
475     DumpManagedObject(flags, objRef);
476
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.
480     EX_TRY
481     {
482         MethodTable * pMethodTable = objRef->GetGCSafeMethodTable();
483         PTR_Module pModule = pMethodTable->GetModule();
484         mdTypeDef exceptionTypeDef = pMethodTable->GetCl();
485
486         if (TypeFromToken(exceptionTypeDef) != mdtTypeDef)
487         {
488             _ASSERTE(!"Module should have contained a TypeDef, dump will likely be missing exception type lookup!");
489         }
490
491         // The lookup from the Module that contains this TypeDef:
492         pModule->LookupTypeDef(RidFromToken(exceptionTypeDef));
493
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
496         // Exception info.
497         TypeHandle th;
498         th = ClassLoader::LookupTypeDefOrRefInModule(pModule, exceptionTypeDef);
499         th.EnumMemoryRegions(flags);
500     }
501     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
502
503 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
504     // store the exception type name
505     EX_TRY
506     {
507         MethodTable * pMethodTable = objRef->GetGCSafeMethodTable();
508         StackSString s;
509         TypeString::AppendType(s, TypeHandle(pMethodTable), TypeString::FormatNamespace|TypeString::FormatFullInst);
510         DacMdCacheAddEEName(dac_cast<TADDR>(pMethodTable), s);
511     }
512     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
513 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
514
515     EXCEPTIONREF exceptRef = (EXCEPTIONREF)objRef;
516
517     if (flags != CLRDATA_ENUM_MEM_TRIAGE)
518     {
519         // dump the exception message field
520         DumpManagedObject(flags, (OBJECTREF)exceptRef->GetMessage());
521     }
522
523     // dump the exception's stack trace field
524     DumpManagedStackTraceStringObject(flags, exceptRef->GetStackTraceString());
525
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 ||
530 #ifdef FEATURE_APPX
531         AppX::DacIsAppXProcess() ||
532 #endif // FEATURE_APPX
533         !ExceptionTypeOverridesStackTraceGetter(exceptRef->GetGCSafeMethodTable()))
534     {
535         DumpManagedStackTraceStringObject(flags, exceptRef->GetRemoteStackTraceString());
536     }
537
538     // Dump inner exception
539     DumpManagedExcepObject(flags, exceptRef->GetInnerException());
540
541     // Dump the stack trace array object and its underlying type
542     I1ARRAYREF stackTraceArrayObj = exceptRef->GetStackTraceArrayObject();
543
544     // There are cases where a managed exception does not have a stack trace.
545     // These cases are:
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)
549     {
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());
556
557         // now dump the actual stack trace array object
558         DumpManagedObject(flags, (OBJECTREF)stackTraceArrayObj);
559     }
560
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
565     // MD this happens.
566     StackTraceArray stackTrace;
567     exceptRef->GetStackTrace(stackTrace);
568     for(size_t i = 0; i < stackTrace.Size(); i++)
569     {
570         MethodDesc* pMD = stackTrace[i].pFunc;
571         if (!DacHasMethodDescBeenEnumerated(pMD) && DacValidateMD(pMD))
572         {
573             pMD->EnumMemoryRegions(flags);
574
575             // The following calls are to ensure that mscordacwks!DacDbiInterfaceImpl::GetNativeCodeInfo
576             // will succeed for all dumps.
577
578             // Pulls in data to translate from token to MethodDesc
579             FindLoadedMethodRefOrDef(pMD->GetMethodTable()->GetModule(), pMD->GetMemberDef());
580
581             // Pulls in sequence points.
582             DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, pMD);
583             PCODE addr = pMD->GetNativeCode();
584             if (addr != NULL)
585             {
586                 IJitManager::MethodRegionInfo methodRegionInfo = { NULL, 0, NULL, 0 };
587                 EECodeInfo codeInfo(addr);
588                 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
589             }
590         }
591
592         // Enumerate the code around call site to help SOS resolve the source lines
593         TADDR callEnd = PCODEToPINSTR(stackTrace[i].ip);
594         DacEnumCodeForStackwalk(callEnd);
595     }
596
597     return S_OK;
598 }
599
600 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
601 //
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.
605 //
606 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
607 HRESULT ClrDataAccess::DumpManagedStackTraceStringObject(CLRDataEnumMemoryFlags flags, STRINGREF orefStackTrace)
608 {
609     SUPPORTS_DAC;
610
611     if (orefStackTrace == NULL)
612     {
613         return S_OK;
614     }
615
616     // dump the stack trace string object
617     DumpManagedObject(flags, (OBJECTREF)orefStackTrace);
618
619     if (flags == CLRDATA_ENUM_MEM_TRIAGE)
620     {
621         // StringObject::GetSString does not support DAC, use GetBuffer/GetStringLength
622         SString stackTrace(dac_cast<PTR_WSTR>((TADDR)orefStackTrace->GetBuffer()), orefStackTrace->GetStringLength());
623
624         StripFileInfoFromStackTrace(stackTrace);
625
626         COUNT_T traceCharCount = stackTrace.GetCount();
627         _ASSERTE(traceCharCount <= orefStackTrace->GetStringLength());
628
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));
632
633         // replace the string
634         DacUpdateMemoryRegion(dac_cast<TADDR>(orefStackTrace) + StringObject::GetBufferOffset(), sizeof(WCHAR) * orefStackTrace->GetStringLength(), (BYTE *)buffer);
635     }
636
637     return S_OK;
638 }
639
640 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
641 //
642 // Iterating through module list and report the memory.
643 // Remember to call
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.
647 //
648 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
649 HRESULT ClrDataAccess::EnumMemDumpModuleList(CLRDataEnumMemoryFlags flags)
650 {
651     SUPPORTS_DAC;
652
653     ProcessModIter  modIter;
654     Module*         modDef;
655     TADDR           base;
656     ULONG32         length;
657     PEFile          *file;
658     TSIZE_T         cbMemoryReported = m_cbMemoryReported;
659 #ifdef FEATURE_PREJIT
660     COUNT_T         count;
661 #endif // FEATURE_PREJIT
662
663     //
664     // Iterating through module list
665     //
666
667     // Cannot use CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED around
668     // conditional pre-processor directives in a sane fashion
669     EX_TRY
670     {
671         while ((modDef = modIter.NextModule()))
672         {
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
676             (
677                 // Pass false to ensure we force enumeration of this module's references.
678                 modDef->EnumMemoryRegions(flags, false);
679             );
680
681             EX_TRY
682             {
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();
689
690                 // Implicitly gets the COR header.
691                 if ((pILImage) && (pILImage->HasLoadedLayout()))
692                 {
693                     pILImage->GetCorHeaderFlags(); 
694                 }
695                 if ((pNIImage) && (pNIImage->HasLoadedLayout()))
696                 {
697                     pNIImage->GetCorHeaderFlags();
698                 }
699             }
700             EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
701
702
703             EX_TRY
704             {
705                 file = modDef->GetFile();
706                 base = PTR_TO_TADDR(file->GetLoadedImageContents(&length));
707                 file->EnumMemoryRegions(flags);
708 #ifdef FEATURE_PREJIT
709
710                 // If module has native image and it has debug map, we need to get the debug map.
711                 //
712                 if (modDef->HasNativeImage() && modDef->GetNativeImage()->HasNativeDebugMap())
713                 {
714                     modDef->GetNativeImage()->GetNativeDebugMap(&count);
715                 }
716 #endif // FEATURE_PREJIT
717             }
718             EX_CATCH
719             {
720                 // Catch the exception and keep going unless COR_E_OPERATIONCANCELED
721                 // was thrown. Used generating dumps, where rethrow will cancel dump.
722             }
723             EX_END_CATCH(RethrowCancelExceptions)
724         }
725     }
726     EX_CATCH
727     {
728         // Catch the exception and keep going unless COR_E_OPERATIONCANCELED
729         // was thrown. Used generating dumps, where rethrow will cancel dump.
730     }
731     EX_END_CATCH(RethrowCancelExceptions)
732
733     m_dumpStats.m_cbModuleList = m_cbMemoryReported - cbMemoryReported;
734
735     return S_OK;
736 }
737
738 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
739 //
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.
743 //
744 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
745 HRESULT ClrDataAccess::EnumMemDumpAppDomainInfo(CLRDataEnumMemoryFlags flags)
746 {
747     SUPPORTS_DAC;
748
749     AppDomainIterator adIter(FALSE);
750     EX_TRY
751     {
752         while (adIter.Next())
753         {
754             CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
755             (
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);
759             );
760         }
761     }
762     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
763
764     return S_OK;
765 }
766
767 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
768 //
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.
773 //
774 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
775 HRESULT ClrDataAccess::EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags,
776                                               IXCLRDataStackWalk  *pStackWalk,
777                                               Thread * pThread)
778 {
779     SUPPORTS_DAC;
780
781 #if defined(DAC_MEASURE_PERF)
782     g_nStackWalk = 1;
783     unsigned __int64 nStart= GetCycleCount();
784 #endif
785
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);
791
792     MethodDesc * pMethodDesc = NULL;
793     EX_TRY
794     {
795         TADDR previousSP = 0; //start at zero; this allows first check to always succeed.
796         TADDR currentSP;
797         currentSP = dac_cast<TADDR>(pThread->GetCachedStackLimit()) + sizeof(TADDR);
798
799         // exhaust the frames using DAC api
800         bool frameHadContext;
801         for (; status == S_OK; )
802         {
803             frameHadContext = false;
804             status = pStackWalk->GetFrame(&pFrame);
805             if (status == S_OK && pFrame != NULL)
806             {
807                 // write out the code that ip pointed to
808                 T_CONTEXT context;
809                 REGDISPLAY regDisp;
810                 if ((status=pFrame->GetContext(CONTEXT_ALL, sizeof(T_CONTEXT),
811                                                    NULL, (BYTE *)&context))==S_OK)
812                 {
813                     // Enumerate the code around the call site to help debugger stack walking heuristics
814                     ::FillRegDisplay(&regDisp, &context);
815                     TADDR callEnd = PCODEToPINSTR(GetControlPC(&regDisp));
816                     DacEnumCodeForStackwalk(callEnd);
817                     frameHadContext = true;
818                 }
819
820                 //
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!
824                 //
825                 CLRDataSimpleFrameType simpleFrameType;
826                 CLRDataDetailedFrameType detailedFrameType;
827                 if (SUCCEEDED(pFrame->GetFrameType(&simpleFrameType, &detailedFrameType)))
828                 {
829                     if (!frameHadContext)
830                     {
831                         _ASSERTE(!"Stack frame should always have an associated context!");
832                         break;
833                     }
834
835                     // This is StackFrameIterator::SFITER_FRAMELESS_METHOD, initialized by Code:ClrDataStackWalk::GetFrame
836                     //  from code:ClrDataStackWalk::RawGetFrameType
837                     if (simpleFrameType == CLRDATA_SIMPFRAME_MANAGED_METHOD)
838                     {
839                         currentSP = (TADDR)GetRegdisplaySP(&regDisp);
840
841                         if (currentSP <= previousSP)
842                         {
843                             _ASSERTE(!"Target stack has been corrupted, SP for current frame must be larger than previous frame.");
844                             break;
845                         }
846
847                         if (currentSP % sizeof(TADDR) != 0)
848                         {
849                             _ASSERTE(!"Target stack has been corrupted, SP must be aligned.");
850                             break;
851                         }
852
853                         if (!pThread->IsAddressInStack(currentSP))
854                         {
855                             _ASSERTE(!"Target stack has been corrupted, SP must in in the stack range.");
856                             break;
857                         }
858                     }
859                 }
860                 else
861                 {
862                     _ASSERTE(!"The stack frame should always know what type it is!");
863                     break;
864                 }
865
866                 status = pFrame->GetMethodInstance(&pMethod);
867                 if (status == S_OK && pMethod != NULL)
868                 {
869                     // managed frame
870                     if (SUCCEEDED(pMethod->GetTypeInstance(&pTypeInstance)) &&
871                         (pTypeInstance != NULL))
872                     {
873                         pTypeInstance.Clear();
874                     }
875
876                     if(SUCCEEDED(pMethod->GetDefinition(&pMethodDefinition)) &&
877                        (pMethodDefinition != NULL))
878                     {
879                         pMethodDesc = ((ClrDataMethodDefinition *)pMethodDefinition.GetValue())->GetMethodDesc();
880                         if (pMethodDesc)
881                         {
882
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.
888                             EX_TRY
889                             {
890                                 if ((pMethodDesc->AcquiresInstMethodTableFromThis()) ||
891                                     (pMethodDesc->RequiresInstMethodTableArg()))
892                                 {
893                                     // MethodTable
894                                     ReleaseHolder<IXCLRDataValue> pDV(NULL);
895                                     ReleaseHolder<IXCLRDataValue> pAssociatedValue(NULL);
896                                     CLRDATA_ADDRESS address;
897                                     PTR_Object pObjThis = NULL;
898
899                                     if (SUCCEEDED(pFrame->GetArgumentByIndex(0, &pDV, 0, NULL, NULL)) &&
900                                         SUCCEEDED(pDV->GetAssociatedValue(&pAssociatedValue)) &&
901                                         SUCCEEDED(pAssociatedValue->GetAddress(&address)))
902                                     {
903                                         // Implicitly enumerate the object itself.
904                                         TADDR addrObjThis = CLRDATA_ADDRESS_TO_TADDR(address);
905                                         pObjThis = dac_cast<PTR_Object>(addrObjThis);
906                                     }
907
908                                     // And now get the extra info we need for the AcquiresInstMethodTableFromThis case.
909                                     if (pMethodDesc->AcquiresInstMethodTableFromThis())
910                                     {
911                                         // When working with the 'this' case, we need to pick up the MethodTable from
912                                         // object lookup.
913                                         PTR_MethodTable pMT = NULL;
914                                         if (pObjThis != NULL)
915                                         {
916                                             pMT = pObjThis->GetMethodTable();
917                                         }
918
919                                         TypeHandle th;
920                                         if (pMT != NULL)
921                                         {
922                                             th = TypeHandle(pMT);
923                                         }
924
925                                         Instantiation classInst = pMethodDesc->GetExactClassInstantiation(th);
926                                         Instantiation methodInst = pMethodDesc->GetMethodInstantiation();
927                                     }
928
929                                 }
930                                 else if (pMethodDesc->RequiresInstMethodDescArg())
931                                 {
932                                     // This method has a generic type token which is required to figure out the exact instantiation
933                                     // of the method.
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);
940
941                                     if (SUCCEEDED(pFrame->QueryInterface(__uuidof(IXCLRDataFrame2), (void**)&pFrame2)) &&
942                                         SUCCEEDED(pFrame2->GetExactGenericArgsToken(&pDV)) &&
943                                         SUCCEEDED(pDV->GetAssociatedValue(&pAssociatedValue)) &&
944                                         SUCCEEDED(pAssociatedValue->GetAddress(&address)))
945                                     {
946                                         TADDR addrMD = CLRDATA_ADDRESS_TO_TADDR(address);
947                                         PTR_MethodDesc pMD = dac_cast<PTR_MethodDesc>(addrMD);
948                                         pMD->EnumMemoryRegions(flags);
949                                     }
950
951                                     pMethodDesc->EnumMemoryRegions(flags);
952                                     MethodTable * pCanonicalMT = pMethodDesc->GetCanonicalMethodTable();
953                                     MethodTable * pNormalMT = pMethodDesc->GetMethodTable();
954                                     pCanonicalMT->EnumMemoryRegions(flags);
955                                     pNormalMT->EnumMemoryRegions(flags);
956                                 }
957                             }
958                             EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
959
960                             pMethodDesc->EnumMemoryRegions(flags);
961
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.
967
968                             // Pulls in sequence points and local variable info
969                             DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, pMethodDesc);
970
971 #ifdef WIN64EXCEPTIONS
972                             PCODE addr = pMethodDesc->GetNativeCode();
973
974                             if (addr != NULL)
975                             {
976                                 EECodeInfo codeInfo(addr);
977
978                                 // We want IsFilterFunclet to work for anything on the stack
979                                 codeInfo.GetJitManager()->IsFilterFunclet(&codeInfo);
980
981                                 // The stackwalker needs GC info to find the parent 'stack pointer' or PSP
982                                 PTR_BYTE pGCInfo = dac_cast<PTR_BYTE>(codeInfo.GetGCInfo());
983                                 if (pGCInfo != NULL)
984                                 {
985                                     GcInfoDecoder gcDecoder(pGCInfo, DECODE_PSP_SYM, 0);
986                                     DacEnumMemoryRegion(dac_cast<TADDR>(pGCInfo), gcDecoder.GetNumBytesRead(), true);
987                                 }
988                             }
989 #endif // WIN64EXCEPTIONS
990                         }
991                         pMethodDefinition.Clear();
992                     }
993                     pMethod.Clear();
994                 }
995                 pFrame.Clear();
996             }
997
998             previousSP = currentSP;
999             status = pStackWalk->Next();
1000         }
1001
1002     }
1003     EX_CATCH
1004     {
1005         status = E_FAIL;
1006         // Catch the exception and keep going unless a COR_E_OPERATIONCANCELED
1007         // was thrown. In which case, rethrow to cancel the dump gathering
1008     }
1009     EX_END_CATCH(RethrowCancelExceptions)
1010
1011 #if defined(DAC_MEASURE_PERF)
1012     unsigned __int64 nEnd = GetCycleCount();
1013     g_nStackTotalTime += nEnd - nStart;
1014     g_nStackWalk = 0;
1015 #endif // #if defined(DAC_MEASURE_PERF)
1016     
1017     return status;
1018 }
1019
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
1024 {
1025 private:
1026
1027     struct TrivialTADDRNode
1028     {
1029         TADDR m_exceptionAddress;
1030         TrivialTADDRNode * m_pNext;
1031
1032         TrivialTADDRNode(TrivialTADDRNode *pNext, TADDR address)
1033             : m_exceptionAddress(address), m_pNext(pNext)
1034         {
1035             SUPPORTS_DAC_HOST_ONLY;
1036         }
1037
1038     private:
1039         TrivialTADDRNode() { _ASSERTE(!"You should never call this ctor."); }
1040     };
1041
1042     TrivialTADDRNode *m_pHead;
1043
1044     bool Find(TADDR address)
1045     {
1046         SUPPORTS_DAC_HOST_ONLY;
1047         for (TrivialTADDRNode *pFind = m_pHead; pFind != NULL; pFind = pFind->m_pNext)
1048             if (pFind->m_exceptionAddress == address)
1049                 return true;
1050
1051         return false;
1052     }
1053
1054 public:
1055     DebuggingExceptionTrackerList()
1056         : m_pHead(NULL)
1057     {
1058         SUPPORTS_DAC_HOST_ONLY;
1059     }
1060
1061     bool AddNewAddressOnly(TADDR address)
1062     {
1063         SUPPORTS_DAC_HOST_ONLY;
1064         if (Find(address))
1065         {
1066             return false;
1067         }
1068         else
1069         {
1070             TrivialTADDRNode *pNew = new TrivialTADDRNode(m_pHead, address);
1071             m_pHead = pNew;
1072             return true;
1073         }
1074     }
1075
1076     ~DebuggingExceptionTrackerList()
1077     {
1078         SUPPORTS_DAC_HOST_ONLY;
1079         for (TrivialTADDRNode *pTemp = m_pHead; m_pHead != NULL; pTemp = m_pHead)
1080         {
1081             m_pHead = m_pHead->m_pNext;
1082             delete pTemp;
1083         }
1084     }
1085 };
1086
1087
1088 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1089 //
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.
1092 // So do call
1093 //      m_instances.DumpAllInstances(m_enumMemCb);
1094 // when function is done.
1095 //
1096 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1097 HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags)
1098 {
1099     SUPPORTS_DAC;
1100
1101 #ifdef FEATURE_COMINTEROP
1102     // Dump the exception object stored in the WinRT stowed exception
1103     EnumMemStowedException(flags);
1104 #endif
1105
1106     HRESULT     status = S_OK;
1107     TSIZE_T     cbMemoryReported = m_cbMemoryReported;
1108
1109 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1110
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
1114     EX_TRY
1115     {
1116         DebuggingExceptionTrackerList exceptionTrackingInner;
1117
1118         CLRDATA_ENUM        handle;
1119         ReleaseHolder<IXCLRDataTask> pIXCLRDataTask(NULL);
1120         ReleaseHolder<IXCLRDataExceptionState> pExcepState(NULL);
1121         Thread              *pThread = NULL;
1122
1123         // enumerating through each thread
1124         StartEnumTasks(&handle);
1125         status = EnumTask(&handle, &pIXCLRDataTask);
1126         for (unsigned nbThreads = 0; status == S_OK && pIXCLRDataTask != NULL; nbThreads++)
1127         {
1128             // Avoid infinite loop if target process is corrupted.
1129             if (nbThreads > 100000)
1130             {
1131                 break;
1132             }
1133             EX_TRY
1134             {
1135                 // get Thread *
1136                 pThread = ((ClrDataTask *)pIXCLRDataTask.GetValue())->GetThread();
1137
1138                 // dump the exception object
1139                 DumpManagedExcepObject(flags, pThread->LastThrownObject());
1140
1141                 // Now probe into the exception info
1142                 status = pIXCLRDataTask->GetCurrentExceptionState(&pExcepState);
1143                 while (status == S_OK && pExcepState != NULL)
1144                 {
1145                     EX_TRY
1146                     {
1147                         // touch the throwable in exception state
1148                         PTR_UNCHECKED_OBJECTREF throwRef(((ClrDataExceptionState *)pExcepState.GetValue())->m_throwable);
1149
1150                         // If we've already attempted enumeration for this exception, it's time to quit.
1151                         if (!exceptionTrackingInner.AddNewAddressOnly(throwRef.GetAddr()))
1152                         {
1153                             break;
1154                         }
1155
1156                         DumpManagedExcepObject(flags, *throwRef);
1157                     }
1158                     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1159
1160                     // get the previous exception
1161                     IXCLRDataExceptionState * pExcepStatePrev = NULL;
1162                     status = pExcepState->GetPrevious(&pExcepStatePrev);
1163
1164                     // Release our current exception object, and transfer ref ownership of the previous
1165                     // exception object into the holder.
1166                     pExcepState = pExcepStatePrev;
1167                 }
1168             }
1169             EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1170
1171             // get next thread
1172             pIXCLRDataTask.Clear();
1173             status = EnumTask(&handle, &pIXCLRDataTask);
1174         }
1175         EndEnumTasks(handle);
1176     }
1177     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1178
1179 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1180
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;
1187
1188     EX_TRY
1189     {
1190         CLRDATA_ENUM        handle;
1191         ReleaseHolder<IXCLRDataTask> pIXCLRDataTask(NULL);
1192         ReleaseHolder<IXCLRDataExceptionState> pExcepState(NULL);
1193         ReleaseHolder<IXCLRDataStackWalk> pStackWalk(NULL);
1194         Thread              *pThread = NULL;
1195
1196         // enumerating through each thread's each frame, dump out some interesting
1197         // code memory needed to debugger to recognize frame
1198         //
1199         ThreadStore::EnumMemoryRegions(flags);
1200
1201         // enumerating through each thread
1202         StartEnumTasks(&handle);
1203         status = EnumTask(&handle, &pIXCLRDataTask);
1204         for (unsigned nbThreads = 0; status == S_OK && pIXCLRDataTask != NULL; nbThreads++)
1205         {
1206             // Avoid infinite loop if target process is corrupted.
1207             if (nbThreads > 100000)
1208             {
1209                 break;
1210             }
1211             EX_TRY
1212             {
1213                 // get Thread *
1214                 pThread = ((ClrDataTask *)pIXCLRDataTask.GetValue())->GetThread();
1215
1216                 // Write out the Thread instance
1217                 DacEnumHostDPtrMem(pThread);
1218
1219                 // Write out the context pointed by the thread
1220                 DacEnumHostDPtrMem(pThread->GetContext());
1221
1222                 // @TODO
1223                 // write TEB pointed by the thread
1224                 // DacEnumHostDPtrMem(pThread->GetTEB());
1225
1226                 // @TODO
1227                 // If CLR is hosted, we want to write out fiber data
1228
1229                 // Dump the managed thread object
1230                 DumpManagedObject(flags, pThread->GetExposedObjectRaw());
1231
1232 #ifndef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1233                 // dump the exception object
1234                 DumpManagedExcepObject(flags, pThread->LastThrownObject());
1235 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1236
1237                 // Stack Walking
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,
1243                             &pStackWalk);
1244                 if (status == S_OK && pStackWalk != NULL)
1245                 {
1246                     status = EnumMemWalkStackHelper(flags, pStackWalk, pThread);
1247                     pStackWalk.Clear();
1248                 }
1249
1250                 // Now probe into the exception info
1251                 status = pIXCLRDataTask->GetCurrentExceptionState(&pExcepState);
1252                 while (status == S_OK && pExcepState != NULL)
1253                 {
1254                     EX_TRY
1255                     {
1256                         // touch the throwable in exception state
1257                         PTR_UNCHECKED_OBJECTREF throwRef(((ClrDataExceptionState *)pExcepState.GetValue())->m_throwable);
1258
1259                         // If we've already attempted enumeration for this exception, it's time to quit.
1260                         if (!exceptionTracking.AddNewAddressOnly(throwRef.GetAddr()))
1261                         {
1262                             break;
1263                         }
1264
1265 #ifndef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1266                         DumpManagedExcepObject(flags, *throwRef);
1267 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1268
1269                         // get the type of the exception
1270                         ReleaseHolder<IXCLRDataValue> pValue(NULL);
1271                         status = pExcepState->GetManagedObject(&pValue);
1272                         if (status == S_OK && pValue != NULL)
1273                         {
1274                             ReleaseHolder<IXCLRDataTypeInstance> pTypeInstance(NULL);
1275                             // Make sure that we can get back a TypeInstance during inspection
1276                             status = pValue->GetType(&pTypeInstance);
1277                             pValue.Clear();
1278                         }
1279
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.
1282                         //
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.
1288                         //
1289                         PTR_CONTEXT pContext = ((ClrDataExceptionState*)pExcepState.GetValue())->GetCurrentContextRecord();
1290                         if (pContext != NULL)
1291                         {
1292                             T_CONTEXT newContext;
1293                             newContext = *pContext;
1294
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,
1297                                         &pStackWalk);
1298                             if (status == S_OK && pStackWalk != NULL)
1299                             {
1300                                 status = pStackWalk->SetContext2(CLRDATA_STACK_SET_CURRENT_CONTEXT, sizeof(T_CONTEXT), (BYTE *) &newContext);
1301                                 if (status == S_OK)
1302                                 {
1303                                     status = EnumMemWalkStackHelper(flags, pStackWalk, pThread);
1304                                 }
1305                                 pStackWalk.Clear();
1306                             }
1307                         }
1308                     }
1309                     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1310
1311                     // get the previous exception
1312                     IXCLRDataExceptionState * pExcepStatePrev = NULL;
1313                     status = pExcepState->GetPrevious(&pExcepStatePrev);
1314
1315                     // Release our current exception object, and transfer ref ownership of the previous
1316                     // exception object into the holder.
1317                     pExcepState = pExcepStatePrev;
1318                 }
1319             }
1320             EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1321
1322             // get next thread
1323             pIXCLRDataTask.Clear();
1324             status = EnumTask(&handle, &pIXCLRDataTask);
1325         }
1326         EndEnumTasks(handle);
1327     }
1328     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1329
1330     // updating the statistics
1331     m_dumpStats.m_cbStack = m_cbMemoryReported - cbMemoryReported;
1332
1333     return status;
1334 }
1335
1336
1337 #ifdef FEATURE_COMINTEROP
1338 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1339 //
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.
1343 // So do call
1344 //      m_instances.DumpAllInstances(m_enumMemCb);
1345 // when function is done.
1346 //
1347 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1348 HRESULT ClrDataAccess::EnumMemStowedException(CLRDataEnumMemoryFlags flags)
1349 {
1350     SUPPORTS_DAC;
1351
1352     ICLRDataTarget3 *pTarget3 = GetLegacyTarget3();
1353     if (pTarget3 == NULL)
1354         return S_OK;
1355
1356     // get the thread that raised the exception
1357     ULONG32 exThreadID = 0;
1358     if (FAILED(pTarget3->GetExceptionThreadID(&exThreadID)) || exThreadID == 0)
1359         return S_OK;
1360
1361     //
1362     // check that the thread is one of the known managed threads
1363     //
1364     BOOL foundThread = FALSE;
1365     CLRDATA_ENUM handle;
1366     ReleaseHolder<IXCLRDataTask> pIXCLRDataTask(NULL);
1367
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)
1372     {
1373         // Avoid infinite loop if target process is corrupted.
1374         if (nbThreads > 100000)
1375         {
1376             break;
1377         }
1378         EX_TRY
1379         {
1380             if (((ClrDataTask *)pIXCLRDataTask.GetValue())->GetThread()->GetOSThreadId() == exThreadID)
1381             {
1382                 // found the thread
1383                 foundThread = TRUE;
1384                 break;
1385             }
1386         }
1387         EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1388
1389         // get next thread
1390         pIXCLRDataTask.Clear();
1391         status = EnumTask(&handle, &pIXCLRDataTask);
1392     }
1393     EndEnumTasks(handle);
1394
1395     if (!foundThread)
1396         return S_OK;
1397
1398
1399     //
1400     // Read the remote stowed exceptions.
1401     //
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.
1407     //
1408     ULONG32 bytesRead = 0;
1409     MINIDUMP_EXCEPTION minidumpException = { 0 };
1410     if (FAILED(pTarget3->GetExceptionRecord(sizeof(MINIDUMP_EXCEPTION), &bytesRead, (PBYTE)&minidumpException)))
1411         return S_OK;
1412
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)
1421     {
1422         return S_OK;
1423     }
1424
1425     for (ULONG i = 0; i < stowedExceptionCount; ++i)
1426     {
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)
1433         {
1434             continue;
1435         }
1436
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)
1443         {
1444             continue;
1445         }
1446
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)
1453         {
1454             continue;
1455         }
1456
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));
1459     }
1460
1461     return S_OK;
1462 }
1463
1464 HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, CLRDATA_ADDRESS ccwPtr)
1465 {
1466     SUPPORTS_DAC;
1467     if (ccwPtr == NULL)
1468         return S_OK;
1469
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)));
1475
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)
1483     {
1484         return S_OK;
1485     }
1486
1487     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
1488     (
1489         ReportMem(vTableAddress + sizeof(PBYTE)* TEAR_OFF_SLOT, sizeof(TADDR));
1490     );
1491
1492     return S_OK;
1493 }
1494 #endif
1495
1496 #define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
1497 #define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
1498
1499 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1500 //
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.
1506 //
1507 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1508 HRESULT ClrDataAccess::EnumMemCLRMainModuleInfo()
1509 {
1510     SUPPORTS_DAC;
1511
1512     HRESULT status = S_OK;
1513
1514     // PEDecoder is DACized, so we just need to touch what we want to
1515     // make subsequent lookup work.
1516     PEDecoder pe(m_globalBase);
1517
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.
1522     UINT i;
1523     for (i = 0; pe.GetDebugDirectoryEntry(i); i++)
1524     {
1525     }
1526
1527     if (i < 1)
1528     {
1529         status = E_UNEXPECTED;
1530         _ASSERTE(!"Collecting dump of target with no debug directory entries!");
1531     }
1532
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
1538     // main module.
1539
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))
1546     {
1547         COUNT_T size = 0;
1548         TADDR pResourceDirData = pe.GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_RESOURCE, &size);
1549
1550         _ASSERTE(size < 0x2000);
1551         ReportMem((TADDR)pResourceDirData, size, true);
1552     }
1553     else
1554     {
1555         // In later releases, we should log the ERROR_RESOURCE_DATA_NOT_FOUND.
1556         status = E_UNEXPECTED;
1557     }
1558
1559     return status;
1560 }
1561
1562
1563 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1564 //
1565 // Generating skinny mini-dump. Skinny mini-dump will only support stack trace, module list,
1566 // and Exception list viewing.
1567 //
1568 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1569 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerSkinny(IN CLRDataEnumMemoryFlags flags)
1570 {
1571     SUPPORTS_DAC;
1572
1573     HRESULT status = S_OK;
1574
1575     // clear all of the previous cached memory
1576     Flush();
1577
1578 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1579     // Enable caching enumerated metadata of interest
1580     InitStreamsForWriting(flags);
1581 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1582
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.
1588
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.
1591
1592     // Iterating to all threads' stacks
1593     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(flags); )
1594
1595     // Iterating to module list.
1596     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(flags); )
1597
1598     //
1599     // iterating through static that we care
1600     //
1601     // collect CLR static
1602     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(flags); )
1603
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;
1607
1608     // Dump AppDomain-specific info needed for MiniDumpNormal.
1609     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAppDomainInfo(flags); )
1610
1611     // Dump the Debugger object data needed
1612     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugger->EnumMemoryRegions(flags); )
1613
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
1618
1619     // Do not let any remaining implicitly enumerated memory leak out.
1620     Flush();
1621
1622     return S_OK;
1623 }
1624
1625 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1626 //
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.
1630 //
1631 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1632 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerMicroTriage(IN CLRDataEnumMemoryFlags flags)
1633 {
1634     SUPPORTS_DAC;
1635
1636     HRESULT status = S_OK;
1637
1638     // clear all of the previous cached memory
1639     Flush();
1640
1641 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1642     // Enable caching enumerated metadata of interest
1643     InitStreamsForWriting(flags);
1644 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1645
1646     // Iterating to all threads' stacks
1647     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(flags); )
1648
1649     // Iterating to module list.
1650     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(flags); )
1651
1652     // collect CLR static
1653     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(flags); )
1654
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;
1658
1659     // Dump AppDomain-specific info needed for triage dumps methods enumeration (k command).
1660     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAppDomainInfo(flags); )
1661
1662     // Dump the Debugger object data needed
1663     CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( g_pDebugger->EnumMemoryRegions(flags); )
1664
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
1669
1670     // Do not let any remaining implicitly enumerated memory leak out.
1671     Flush();
1672
1673     return S_OK;
1674 }
1675
1676 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1677 //
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. 
1682 //
1683 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1684 HRESULT ClrDataAccess::EnumMemWriteDataSegment()
1685 {
1686     SUPPORTS_DAC;
1687
1688     NewHolder<PEDecoder> pedecoder(NULL);
1689
1690     EX_TRY
1691     {
1692         // Collecting mscorwks's data segment
1693         {
1694             // m_globalBase is the base address of target process's mscorwks module
1695             pedecoder = new PEDecoder(dac_cast<PTR_VOID>(m_globalBase));
1696
1697             PTR_IMAGE_SECTION_HEADER pSection = (PTR_IMAGE_SECTION_HEADER) pedecoder->FindFirstSection();
1698             PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(pedecoder->GetNumberOfSections());
1699
1700             while (pSection < pSectionEnd)
1701             {
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')
1707                 {   
1708                     // This is the .data section of mscorwks
1709                     ReportMem(m_globalBase + pSection->VirtualAddress, pSection->Misc.VirtualSize);
1710                 }
1711                 pSection++;
1712              }
1713         }
1714     }
1715     EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
1716
1717     return S_OK;        
1718 }    
1719
1720 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1721 //
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. 
1725 //
1726 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1727 HRESULT ClrDataAccess::EnumMemoryRegionsWorkerCustom()
1728 {
1729     SUPPORTS_DAC;
1730
1731     HRESULT status = S_OK;
1732     
1733     ECustomDumpFlavor eFlavor;
1734
1735 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
1736     eFlavor = CCLRErrorReportingManager::g_ECustomDumpFlavor;
1737 #else
1738     eFlavor = DUMP_FLAVOR_Default;
1739 #endif
1740
1741     m_enumMemFlags = CLRDATA_ENUM_MEM_MINI;
1742
1743     // clear all of the previous cached memory
1744     Flush();
1745
1746     if (eFlavor == DUMP_FLAVOR_Mini)
1747     {
1748         // Iterating to all threads' stacks
1749         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(m_enumMemFlags); )
1750
1751         // Iterating to module list.
1752         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(m_enumMemFlags); )
1753
1754         //
1755         // iterating through static that we care
1756         //
1757         // collect CLR static
1758         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); )
1759
1760         // we are done...
1761
1762         // now dump the memory get dragged in implicitly
1763         m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
1764
1765     }
1766     else if (eFlavor == DUMP_FLAVOR_CriticalCLRState)
1767     {
1768         // We need to walk Threads stack to view managed frames.
1769         // Iterating through module list
1770
1771         // Iterating to all threads' stacks
1772         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAllThreadsStack(m_enumMemFlags); )
1773
1774         // Iterating to module list.
1775         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpModuleList(m_enumMemFlags); )
1776
1777         //
1778         // iterating through static that we care
1779         //
1780         // collect CLR static
1781         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); )
1782
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(); )
1786
1787         // we are done...
1788
1789         // now dump the memory get dragged in implicitly
1790         m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
1791
1792     }
1793     else if (eFlavor == DUMP_FLAVOR_NonHeapCLRState)
1794     {
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.
1798         //
1799         // Thus we only need to include mscorwks's critical data and ngen images
1800
1801         m_enumMemFlags = CLRDATA_ENUM_MEM_HEAP;
1802
1803         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(m_enumMemFlags); )
1804
1805         // Collecting some CLR secondary critical data
1806         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRHeapCrticalStatic(m_enumMemFlags); )
1807
1808         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemWriteDataSegment(); )
1809         CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCollectImages(); )
1810     }
1811     else
1812     {
1813         status = E_INVALIDARG;
1814     }
1815
1816     status = m_memStatus;
1817
1818     return S_OK;
1819 }
1820
1821 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1822 //
1823 // Minidumps traverse a giant static calltree. We already try to catch
1824 // exceptions at various lower level places and continue to report memory.
1825 //
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.
1833 //
1834 // Internal API to support minidump and heap dump. It just delegate
1835 // to proper function but with a top level catch. 
1836 //
1837 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1838 HRESULT ClrDataAccess::EnumMemoryRegionsWrapper(IN CLRDataEnumMemoryFlags flags)
1839 {
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;
1844
1845     HRESULT status = S_OK;
1846     m_enumMemFlags = flags;
1847     EX_TRY
1848     {
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)
1853         {
1854             // skinny mini-dump
1855             status = EnumMemoryRegionsWorkerSkinny(flags);
1856         }
1857         else if ( flags == CLRDATA_ENUM_MEM_TRIAGE)
1858         {
1859             // triage micro-dump
1860             status = EnumMemoryRegionsWorkerMicroTriage(flags);
1861         }
1862         else if ( flags == CLRDATA_ENUM_MEM_HEAP)
1863         {
1864             status = EnumMemoryRegionsWorkerHeap(flags);
1865         }
1866         else
1867         {
1868             _ASSERTE(!"Bad flags passing to EnumMemoryRegionsWrapper!");
1869         }
1870     }
1871     EX_CATCH_HRESULT(status);
1872
1873     // The only exception that should reach here is the cancel exception
1874     _ASSERTE(SUCCEEDED(status) || status == COR_E_OPERATIONCANCELED);
1875     
1876     return status;
1877 }
1878
1879 #define     MiniDumpWithPrivateReadWriteMemory     0x00000200
1880 #define     MiniDumpWithFullAuxiliaryState         0x00008000
1881 #define     MiniDumpFilterTriage                   0x00100000
1882
1883
1884
1885 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1886 //
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. 
1891 //
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.
1902 //
1903 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1904 STDMETHODIMP
1905 ClrDataAccess::EnumMemoryRegions(IN ICLRDataEnumMemoryRegionsCallback* callback,
1906                                  IN ULONG32 miniDumpFlags,
1907                                  IN CLRDataEnumMemoryFlags flags)    // reserved not used
1908 {
1909     SUPPORTS_DAC;
1910     HRESULT status;
1911
1912 #if defined(DAC_MEASURE_PERF)
1913
1914     g_nTotalTime = 0;
1915     g_nStackTotalTime = 0;
1916     g_nReadVirtualTotalTime = 0;
1917     g_nFindTotalTime = 0;
1918     g_nFindHashTotalTime = 0;
1919     g_nFindHits = 0;
1920     g_nFindCalls = 0;
1921     g_nFindFails = 0;
1922     g_nStackWalk = 0;
1923     g_nFindStackTotalTime = 0;
1924
1925     LARGE_INTEGER nClockFrequency;
1926     unsigned __int64 nStart = 0;
1927     unsigned __int64 nEnd = 0;
1928     
1929     QueryPerformanceFrequency(&nClockFrequency);
1930
1931     FILE* fp = fopen("c:\\dumpLog.txt", "a");
1932     if (fp)
1933     {
1934         fprintf(fp, "\nMinidumpFlags = %d\n", miniDumpFlags);
1935         fclose(fp);
1936     }
1937     
1938     nStart = GetCycleCount();
1939     
1940 #endif // #if defined(DAC_MEASURE_PERF)
1941
1942     DAC_ENTER();
1943
1944     // We should not be trying to enumerate while we have an enumeration outstanding
1945     _ASSERTE(m_enumMemCb==NULL);
1946     m_memStatus = S_OK;
1947     m_enumMemCb = callback;
1948
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);
1952
1953     EX_TRY
1954     {
1955         ClearDumpStats();
1956         if (miniDumpFlags & MiniDumpWithPrivateReadWriteMemory)
1957         {
1958             // heap dump
1959             status = EnumMemoryRegionsWrapper(CLRDATA_ENUM_MEM_HEAP);
1960         }
1961         else if (miniDumpFlags & MiniDumpWithFullAuxiliaryState)
1962         {
1963             // This is the host custom dump.
1964             status = EnumMemoryRegionsWorkerCustom();
1965         }
1966         else if (miniDumpFlags & MiniDumpFilterTriage)
1967         {
1968             // triage micro-dump
1969             status = EnumMemoryRegionsWrapper(CLRDATA_ENUM_MEM_TRIAGE);
1970         }
1971         else
1972         {
1973             // minidump
1974             status = EnumMemoryRegionsWrapper(CLRDATA_ENUM_MEM_MINI);
1975         }
1976
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))
1982         {
1983             // In case there's implicitly enumerated memory hanging around
1984             // let's not accidentally pick it up.
1985             Flush();
1986             if (SUCCEEDED(status = EnumMemCLRMainModuleInfo()))
1987             {
1988                 m_instances.DumpAllInstances(m_enumMemCb);
1989             }
1990         }
1991
1992         Flush();
1993     }
1994     EX_CATCH
1995     {
1996         m_enumMemCb = NULL;
1997
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
2000         // own exceptions.
2001         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
2002         {
2003             _ASSERTE_MSG(false, "Got unexpected exception in EnumMemoryRegions");
2004             EX_RETHROW;
2005         }
2006     }
2007     EX_END_CATCH(SwallowAllExceptions)
2008
2009     // fix for issue 866100: DAC is too late in releasing ICLRDataEnumMemoryRegionsCallback2*
2010     if (m_updateMemCb)
2011     {
2012         m_updateMemCb->Release();
2013         m_updateMemCb = NULL;
2014     }
2015     m_enumMemCb = NULL;
2016
2017     DAC_LEAVE();
2018
2019 #if defined(DAC_MEASURE_PERF)
2020
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
2033                );
2034     fclose(fp);
2035
2036 #endif // #if defined(DAC_MEASURE_PERF)
2037     
2038     return status;
2039 }
2040
2041
2042 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2043 //
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. 
2048 //
2049 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2050 void ClrDataAccess::ClearDumpStats()
2051 {
2052     SUPPORTS_DAC;
2053
2054     m_cbMemoryReported = 0;
2055     memset(&m_dumpStats, 0, sizeof(DumpMemoryReportStatics));
2056 }