Remove superfluous 'const' qualifier from trivial return types (#20652)
[platform/upstream/coreclr.git] / src / vm / eventtrace.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5 // File: eventtrace.cpp
6 // Abstract: This module implements Event Tracing support
7 //
8
9 //
10
11 //
12 // ============================================================================
13
14 #include "common.h"
15
16 #ifdef FEATURE_REDHAWK
17
18 #include "commontypes.h"
19 #include "daccess.h"
20 #include "debugmacrosext.h"
21 #include "palredhawkcommon.h"
22 #include "gcrhenv.h"
23 #define Win32EventWrite PalEtwEventWrite
24 #define InterlockedExchange64 PalInterlockedExchange64
25
26 #else // !FEATURE_REDHAWK
27
28 #include "eventtrace.h"
29 #include "winbase.h"
30 #include "contract.h"
31 #include "ex.h"
32 #include "dbginterface.h"
33 #include "finalizerthread.h"
34
35 #define Win32EventWrite EventWrite
36
37 #ifdef FEATURE_COMINTEROP
38 #include "comcallablewrapper.h"
39 #include "runtimecallablewrapper.h"
40 #endif
41
42 // Flags used to store some runtime information for Event Tracing
43 BOOL g_fEEOtherStartup=FALSE;
44 BOOL g_fEEComActivatedStartup=FALSE;
45 GUID g_EEComObjectGuid=GUID_NULL;
46
47 BOOL g_fEEHostedStartup = FALSE;
48
49 #endif // FEATURE_REDHAWK
50
51 #include "eventtracepriv.h"
52
53 #ifdef FEATURE_REDHAWK
54 volatile LONGLONG ETW::GCLog::s_l64LastClientSequenceNumber = 0;
55 #else // FEATURE_REDHAWK
56 Volatile<LONGLONG> ETW::GCLog::s_l64LastClientSequenceNumber = 0;
57 #endif // FEATURE_REDHAWK
58
59 #ifndef FEATURE_REDHAWK
60
61 //---------------------------------------------------------------------------------------
62 // Helper macros to determine which version of the Method events to use
63 //
64 // The V2 versions of these events include the ReJITID, the V1 versions do not.
65 // Historically, when we version events, we'd just stop sending the old version and only
66 // send the new one. However, now that we have xperf in heavy use internally and soon to be
67 // used externally, we need to be a bit careful. In particular, we'd like to allow
68 // current xperf to continue working without knowledge of ReJITIDs, and allow future
69 // xperf to decode symbols in ReJITted functions. Thus,
70 //    * During a first-JIT, only issue the existing V1 MethodLoad, etc. events (NOT v0,
71 //        NOT v2). This event does not include a ReJITID, and can thus continue to be
72 //        parsed by older decoders.
73 //    * During a rejit, only issue the new V2 events (NOT v0 or v1), which will include a
74 //        nonzero ReJITID. Thus, your unique key for a method extent would be MethodID +
75 //        ReJITID + extent (hot/cold). These events will be ignored by older decoders
76 //        (including current xperf) because of the version number, but xperf will be
77 //        updated to decode these in the future.
78
79 #define FireEtwMethodLoadVerbose_V1_or_V2(ullMethodIdentifier, ullModuleID, ullMethodStartAddress, ulMethodSize, ulMethodToken, ulMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID) \
80 {   \
81     if (rejitID == 0)   \
82         { FireEtwMethodLoadVerbose_V1(ullMethodIdentifier, ullModuleID, ullMethodStartAddress, ulMethodSize, ulMethodToken, ulMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID); } \
83     else \
84         { FireEtwMethodLoadVerbose_V2(ullMethodIdentifier, ullModuleID, ullMethodStartAddress, ulMethodSize, ulMethodToken, ulMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID); } \
85 }
86
87 #define FireEtwMethodLoad_V1_or_V2(ullMethodIdentifier, ullModuleID, ullMethodStartAddress, ulMethodSize, ulMethodToken, ulMethodFlags, clrInstanceID, rejitID) \
88 {   \
89     if (rejitID == 0)   \
90         { FireEtwMethodLoad_V1(ullMethodIdentifier, ullModuleID, ullMethodStartAddress, ulMethodSize, ulMethodToken, ulMethodFlags, clrInstanceID); } \
91     else \
92         { FireEtwMethodLoad_V2(ullMethodIdentifier, ullModuleID, ullMethodStartAddress, ulMethodSize, ulMethodToken, ulMethodFlags, clrInstanceID, rejitID); } \
93 }
94
95 #define FireEtwMethodUnloadVerbose_V1_or_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID) \
96 {   \
97     if (rejitID == 0)   \
98         { FireEtwMethodUnloadVerbose_V1(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID); } \
99     else \
100         { FireEtwMethodUnloadVerbose_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID); } \
101 }
102
103 #define FireEtwMethodUnload_V1_or_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID, rejitID) \
104 {   \
105     if (rejitID == 0)   \
106         { FireEtwMethodUnload_V1(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID); } \
107     else \
108         { FireEtwMethodUnload_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID, rejitID); } \
109 }
110
111 #define FireEtwMethodDCStartVerbose_V1_or_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID) \
112 {   \
113     if (rejitID == 0)   \
114         { FireEtwMethodDCStartVerbose_V1(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID); } \
115     else \
116         { FireEtwMethodDCStartVerbose_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID); } \
117 }
118
119 #define FireEtwMethodDCStart_V1_or_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID, rejitID) \
120 {   \
121     if (rejitID == 0)   \
122         { FireEtwMethodDCStart_V1(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID); } \
123     else \
124         { FireEtwMethodDCStart_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID, rejitID); } \
125 }
126
127 #define FireEtwMethodDCEndVerbose_V1_or_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID) \
128 {   \
129     if (rejitID == 0)   \
130         { FireEtwMethodDCEndVerbose_V1(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID);  } \
131     else \
132         { FireEtwMethodDCEndVerbose_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, szDtraceOutput1, szDtraceOutput2, szDtraceOutput3, clrInstanceID, rejitID); } \
133 }
134
135 #define FireEtwMethodDCEnd_V1_or_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID, rejitID) \
136 {   \
137     if (rejitID == 0)   \
138         { FireEtwMethodDCEnd_V1(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID);  } \
139     else \
140         { FireEtwMethodDCEnd_V2(ullMethodIdentifier, ullModuleID, ullColdMethodStartAddress, ulColdMethodSize, ulMethodToken, ulColdMethodFlags, clrInstanceID, rejitID); } \
141 }
142
143 // Module load / unload events:
144
145 #define FireEtwModuleLoad_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath) \
146     FireEtwModuleLoad_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath)
147 #define FireEtwModuleUnload_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath) \
148     FireEtwModuleUnload_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath)
149 #define FireEtwModuleDCStart_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath) \
150     FireEtwModuleDCStart_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath)
151 #define FireEtwModuleDCEnd_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath) \
152     FireEtwModuleDCEnd_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, clrInstanceId, ManagedPdbSignature, ManagedPdbAge, ManagedPdbPath, NativePdbSignature, NativePdbAge, NativePdbPath)
153
154
155
156 //---------------------------------------------------------------------------------------
157 //
158 // Rather than checking the NGEN keyword on the runtime provider directly, use this
159 // helper that checks that the NGEN runtime provider keyword is enabled AND the
160 // OverrideAndSuppressNGenEvents keyword on the runtime provider is NOT enabled.
161 // 
162 // OverrideAndSuppressNGenEvents allows controllers to set the expensive NGEN keyword for
163 // older runtimes (< 4.0) where NGEN PDB info is NOT available, while suppressing those
164 // expensive events on newer runtimes (>= 4.5) where NGEN PDB info IS available. Note
165 // that 4.0 has NGEN PDBS but unfortunately not the OverrideAndSuppressNGenEvents
166 // keyword, b/c NGEN PDBs were made publicly only after 4.0 shipped. So tools that need
167 // to consume both <4.0 and 4.0 events would neeed to enable the expensive NGEN events to
168 // deal properly with 3.5, even though those events aren't necessary on 4.0.
169 // 
170 // On CoreCLR, this keyword is a no-op, because coregen PDBs don't exist (and thus we'll
171 // need the NGEN rundown to still work on Silverligth).
172 //
173 // Return Value:
174 //      nonzero iff NGenKeyword is enabled on the runtime provider and
175 //      OverrideAndSuppressNGenEventsKeyword is not enabled on the runtime provider.
176 //
177
178 BOOL IsRuntimeNgenKeywordEnabledAndNotSuppressed()
179 {
180     LIMITED_METHOD_CONTRACT;
181
182     return 
183     (
184         ETW_TRACING_CATEGORY_ENABLED(
185             MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
186             TRACE_LEVEL_INFORMATION, 
187             CLR_NGEN_KEYWORD) 
188         && ! ( ETW_TRACING_CATEGORY_ENABLED(
189                 MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
190                 TRACE_LEVEL_INFORMATION, 
191                 CLR_OVERRIDEANDSUPPRESSNGENEVENTS_KEYWORD) )
192     );
193 }
194
195 // Same as above, but for the rundown provider
196 BOOL IsRundownNgenKeywordEnabledAndNotSuppressed()
197 {
198     LIMITED_METHOD_CONTRACT;
199
200     return
201 #ifdef FEATURE_PERFTRACING
202         EventPipeHelper::Enabled() ||
203 #endif // FEATURE_PERFTRACING
204     (
205         ETW_TRACING_CATEGORY_ENABLED(
206             MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
207             TRACE_LEVEL_INFORMATION, 
208             CLR_RUNDOWNNGEN_KEYWORD)
209         && ! ( ETW_TRACING_CATEGORY_ENABLED(
210                 MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
211                 TRACE_LEVEL_INFORMATION, 
212                 CLR_RUNDOWNOVERRIDEANDSUPPRESSNGENEVENTS_KEYWORD) )
213     );
214 }
215
216 /*******************************************************/
217 /* Fast assembly function to get the topmost EBP frame */
218 /*******************************************************/
219 #if defined(_TARGET_X86_)
220 extern "C"
221 {
222     CallStackFrame* GetEbp()
223     {
224         CallStackFrame *frame=NULL;
225         __asm
226         { 
227             mov frame, ebp
228         } 
229         return frame;
230     }
231 }
232 #endif //_TARGET_X86_
233
234 /*************************************/
235 /* Function to append a frame to an existing stack */
236 /*************************************/
237 #if  !defined(FEATURE_PAL)
238 void ETW::SamplingLog::Append(SIZE_T currentFrame)
239 {
240     LIMITED_METHOD_CONTRACT;
241     if(m_FrameCount < (ETW::SamplingLog::s_MaxStackSize-1) && 
242        currentFrame != 0)
243     {
244         m_EBPStack[m_FrameCount] = currentFrame;
245         m_FrameCount++;
246     }
247 };
248
249 /********************************************************/
250 /* Function to get the callstack on the current thread  */
251 /********************************************************/
252 ETW::SamplingLog::EtwStackWalkStatus ETW::SamplingLog::GetCurrentThreadsCallStack(UINT32 *frameCount, PVOID **Stack)
253 {    
254     CONTRACTL
255     {
256         NOTHROW;
257         GC_NOTRIGGER;
258         MODE_ANY;
259         SO_TOLERANT;
260     }
261     CONTRACTL_END;
262
263     // The stack walk performed below can cause allocations (thus entering the host). But
264     // this is acceptable, since we're not supporting the use of SQL/F1 profiling and
265     // full-blown ETW CLR stacks (which would be redundant).
266     PERMANENT_CONTRACT_VIOLATION(HostViolation, ReasonUnsupportedForSQLF1Profiling);
267
268     m_FrameCount = 0;
269     ETW::SamplingLog::EtwStackWalkStatus stackwalkStatus = SaveCurrentStack();
270
271     _ASSERTE(m_FrameCount < ETW::SamplingLog::s_MaxStackSize);
272
273     // this not really needed, but let's do it 
274     // because we use the framecount while dumping the stack event
275     for(int i=m_FrameCount; i<ETW::SamplingLog::s_MaxStackSize; i++)
276     {
277         m_EBPStack[i] = 0;
278     }
279     // This is for consumers to work correctly because the number of 
280     // frames in the manifest file is specified to be 2
281     if(m_FrameCount < 2)
282         m_FrameCount = 2;
283
284     *frameCount = m_FrameCount;
285     *Stack = (PVOID *)m_EBPStack;
286     return stackwalkStatus;
287 };
288
289 /*************************************/
290 /* Function to save the stack on the current thread */
291 /*************************************/
292 ETW::SamplingLog::EtwStackWalkStatus ETW::SamplingLog::SaveCurrentStack(int skipTopNFrames)
293 {
294     CONTRACTL
295     {
296         NOTHROW;
297         GC_NOTRIGGER;
298         MODE_ANY;
299         SO_TOLERANT;
300     }
301     CONTRACTL_END;
302
303     if (!IsGarbageCollectorFullyInitialized())
304     {
305         // If the GC isn't ready yet, then there won't be any interesting
306         // managed code on the stack to walk. Plus, the stack walk itself may
307         // hit problems (e.g., when calling into the code manager) if it's run
308         // too early during startup.
309         return ETW::SamplingLog::UnInitialized;
310     }
311 #ifndef DACCESS_COMPILE
312 #ifdef _TARGET_AMD64_
313     if (RtlVirtualUnwind_Unsafe == NULL)
314     {
315         // We haven't even set up the RtlVirtualUnwind function pointer yet,
316         // so it's too early to try stack walking.
317         return ETW::SamplingLog::UnInitialized;
318     }
319 #endif // _TARGET_AMD64_
320     Thread *pThread = GetThread();
321     if (pThread == NULL)
322     {
323         return ETW::SamplingLog::UnInitialized;
324     }    
325     // The thread should not have a hijack set up or we can't walk the stack. 
326     if (pThread->m_State & Thread::TS_Hijacked) {
327         return ETW::SamplingLog::UnInitialized;
328     }
329     if (pThread->IsEtwStackWalkInProgress())
330     {
331         return ETW::SamplingLog::InProgress;
332     }
333     pThread->MarkEtwStackWalkInProgress();
334     EX_TRY
335     {
336 #ifdef _TARGET_X86_
337         CallStackFrame *currentEBP = GetEbp();
338         CallStackFrame *lastEBP = NULL;
339
340         // The EBP stack walk below is meant to be extremely fast. It does not attempt to protect
341         // against cases of stack corruption. *BUT* it does need to validate a "sane" EBP chain.
342
343         // Ensure the EBP in the starting frame is "reasonable" (i.e. above the address of a local)
344         if ((SIZE_T) currentEBP > (SIZE_T)&currentEBP)
345         {
346             while(currentEBP)
347             {
348                 lastEBP = currentEBP;
349                 currentEBP = currentEBP->m_Next;
350                 
351                 // Check for stack upper limit; we don't check the lower limit on each iteration 
352                 // (we did it at the top) and each subsequent value in the loop is larger than 
353                 // the previous (see the check "currentEBP < lastEBP" below)
354                 if((SIZE_T)currentEBP > (SIZE_T)Thread::GetStackUpperBound())
355                 {
356                     break;
357                 }
358         
359                 // If we have a too small address, we are probably bad
360                 if((SIZE_T)currentEBP < (SIZE_T)0x10000)
361                     break;
362         
363                 if((SIZE_T)currentEBP < (SIZE_T)lastEBP)
364                 {
365                     break;
366                 }
367         
368                 // Skip the top N frames
369                 if(skipTopNFrames) {
370                     skipTopNFrames--;
371                     continue;
372                 }
373         
374                 // Save the Return Address for symbol decoding
375                 Append(lastEBP->m_ReturnAddress);
376             }
377         }
378 #else
379         CONTEXT ctx;
380         ClrCaptureContext(&ctx);
381         UINT_PTR ControlPc = 0;
382         UINT_PTR CurrentSP = 0, PrevSP = 0;
383
384         while(1)
385         {
386             // Unwind to the caller
387             ControlPc = Thread::VirtualUnwindCallFrame(&ctx);
388     
389             // This is to take care of recursion
390             CurrentSP = (UINT_PTR)GetSP(&ctx);
391
392             // when to break from this loop
393             if ( ControlPc == 0 || ( PrevSP == CurrentSP ) )
394             {
395                 break;
396             }
397     
398             // Skip the top N frames
399             if ( skipTopNFrames ) {
400                 skipTopNFrames--;
401                 continue;
402             }
403     
404             // Add the stack frame to the list
405             Append(ControlPc);
406     
407             PrevSP = CurrentSP;
408         }
409 #endif //_TARGET_X86_
410     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
411     pThread->MarkEtwStackWalkCompleted();
412 #endif //!DACCESS_COMPILE
413
414     return ETW::SamplingLog::Completed;
415 }
416
417 #endif // !defined(FEATURE_PAL)
418 #endif // !FEATURE_REDHAWK
419
420 /****************************************************************************/
421 /* Methods that are called from the runtime */
422 /****************************************************************************/
423
424 /****************************************************************************/
425 /* Methods for rundown events                                               */
426 /****************************************************************************/
427
428 /***************************************************************************/
429 /* This function should be called from the event tracing callback routine 
430    when the private CLR provider is enabled */
431 /***************************************************************************/
432
433 #ifndef FEATURE_REDHAWK
434
435 VOID ETW::GCLog::GCSettingsEvent()
436 {
437     if (GCHeapUtilities::IsGCHeapInitialized())
438     {
439         if (ETW_TRACING_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, 
440                                                  GCSettings))
441         {
442             ETW::GCLog::ETW_GC_INFO Info;
443
444             Info.GCSettings.ServerGC = GCHeapUtilities::IsServerHeap ();
445             Info.GCSettings.SegmentSize = GCHeapUtilities::GetGCHeap()->GetValidSegmentSize (false);
446             Info.GCSettings.LargeObjectSegmentSize = GCHeapUtilities::GetGCHeap()->GetValidSegmentSize (true);
447             FireEtwGCSettings_V1(Info.GCSettings.SegmentSize, Info.GCSettings.LargeObjectSegmentSize, Info.GCSettings.ServerGC, GetClrInstanceId());
448         }  
449         GCHeapUtilities::GetGCHeap()->DiagTraceGCSegments();
450     }
451 };
452
453 #endif // !FEATURE_REDHAWK
454
455
456 //---------------------------------------------------------------------------------------
457 // Code for sending GC heap object events is generally the same for both FEATURE_REDHAWK
458 // and !FEATURE_REDHAWK builds
459 //---------------------------------------------------------------------------------------
460
461 bool s_forcedGCInProgress = false;
462 class ForcedGCHolder
463 {
464 public:
465     ForcedGCHolder() { LIMITED_METHOD_CONTRACT; s_forcedGCInProgress = true; }
466     ~ForcedGCHolder() { LIMITED_METHOD_CONTRACT; s_forcedGCInProgress = false; }
467 };
468
469 BOOL ETW::GCLog::ShouldWalkStaticsAndCOMForEtw()
470 {
471     LIMITED_METHOD_CONTRACT;
472     
473     return s_forcedGCInProgress &&
474         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
475                                      TRACE_LEVEL_INFORMATION,
476                                      CLR_GCHEAPDUMP_KEYWORD);
477 }
478
479 // Simple helpers called by the GC to decide whether it needs to do a walk of heap
480 // objects and / or roots.
481
482 BOOL ETW::GCLog::ShouldWalkHeapObjectsForEtw()
483 {
484     LIMITED_METHOD_CONTRACT;
485     return s_forcedGCInProgress &&
486         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
487                                      TRACE_LEVEL_INFORMATION, 
488                                      CLR_GCHEAPDUMP_KEYWORD);
489 }
490
491 BOOL ETW::GCLog::ShouldWalkHeapRootsForEtw()
492 {
493     LIMITED_METHOD_CONTRACT;
494     return s_forcedGCInProgress &&
495         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
496                                      TRACE_LEVEL_INFORMATION,
497                                      CLR_GCHEAPDUMP_KEYWORD);
498 }
499
500 BOOL ETW::GCLog::ShouldTrackMovementForEtw()
501 {
502     LIMITED_METHOD_CONTRACT;
503     return ETW_TRACING_CATEGORY_ENABLED(
504         MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
505         TRACE_LEVEL_INFORMATION, 
506         CLR_GCHEAPSURVIVALANDMOVEMENT_KEYWORD);
507 }
508
509 // Batches the list of moved/surviving references for the GCBulkMovedObjectRanges /
510 // GCBulkSurvivingObjectRanges events
511 struct EtwGcMovementContext
512 {
513 public:
514     // An instance of EtwGcMovementContext is dynamically allocated and stored
515     // inside of MovedReferenceContextForEtwAndProfapi, which in turn is dynamically
516     // allocated and pointed to by a profiling_context pointer created by the GC on the stack.
517     // This is used to batch and send GCBulkSurvivingObjectRanges events and
518     // GCBulkMovedObjectRanges events. This method is passed a pointer to
519     // MovedReferenceContextForEtwAndProfapi::pctxEtw; if non-NULL it gets returned;
520     // else, a new EtwGcMovementContext is allocated, stored in that pointer, and
521     // then returned. Callers should test for NULL, which can be returned if out of
522     // memory
523     static EtwGcMovementContext * GetOrCreateInGCContext(EtwGcMovementContext ** ppContext)
524     {
525         LIMITED_METHOD_CONTRACT;
526
527         _ASSERTE(ppContext != NULL);
528
529         EtwGcMovementContext * pContext = *ppContext;
530         if (pContext == NULL)
531         {
532             pContext = new (nothrow) EtwGcMovementContext;
533             *ppContext = pContext;
534         }
535         return pContext;
536     }
537
538     EtwGcMovementContext() :
539         iCurBulkSurvivingObjectRanges(0),
540         iCurBulkMovedObjectRanges(0)
541     {
542         LIMITED_METHOD_CONTRACT;
543         Clear();
544     }
545
546     // Resets structure for reuse on construction, and after each flush.
547     // (Intentionally leave iCurBulk* as is, since they persist across flushes within a GC.)
548     void Clear()
549     {
550         LIMITED_METHOD_CONTRACT;
551         cBulkSurvivingObjectRanges = 0;
552         cBulkMovedObjectRanges = 0;
553         ZeroMemory(rgGCBulkSurvivingObjectRanges, sizeof(rgGCBulkSurvivingObjectRanges));
554         ZeroMemory(rgGCBulkMovedObjectRanges, sizeof(rgGCBulkMovedObjectRanges));
555     }
556
557     //---------------------------------------------------------------------------------------
558     // GCBulkSurvivingObjectRanges
559     //---------------------------------------------------------------------------------------
560
561     // Sequence number for each GCBulkSurvivingObjectRanges event
562     UINT iCurBulkSurvivingObjectRanges;
563
564     // Number of surviving object ranges currently filled out in rgGCBulkSurvivingObjectRanges array
565     UINT cBulkSurvivingObjectRanges;
566
567     // Struct array containing the primary data for each GCBulkSurvivingObjectRanges
568     // event. Fix the size so the total event stays well below the 64K limit (leaving
569     // lots of room for non-struct fields that come before the values data)
570     EventStructGCBulkSurvivingObjectRangesValue rgGCBulkSurvivingObjectRanges[
571         (cbMaxEtwEvent - 0x100) / sizeof(EventStructGCBulkSurvivingObjectRangesValue)];
572
573     //---------------------------------------------------------------------------------------
574     // GCBulkMovedObjectRanges
575     //---------------------------------------------------------------------------------------
576
577     // Sequence number for each GCBulkMovedObjectRanges event
578     UINT iCurBulkMovedObjectRanges;
579
580     // Number of Moved object ranges currently filled out in rgGCBulkMovedObjectRanges array
581     UINT cBulkMovedObjectRanges;
582
583     // Struct array containing the primary data for each GCBulkMovedObjectRanges
584     // event. Fix the size so the total event stays well below the 64K limit (leaving
585     // lots of room for non-struct fields that come before the values data)
586     EventStructGCBulkMovedObjectRangesValue rgGCBulkMovedObjectRanges[
587         (cbMaxEtwEvent - 0x100) / sizeof(EventStructGCBulkMovedObjectRangesValue)];
588 };
589
590 // Contains above struct for ETW, plus extra info (opaque to us) used by the profiling
591 // API to track its own information.
592 struct MovedReferenceContextForEtwAndProfapi
593 {
594     // An instance of MovedReferenceContextForEtwAndProfapi is dynamically allocated and
595     // pointed to by a profiling_context pointer created by the GC on the stack. This is used to
596     // batch and send GCBulkSurvivingObjectRanges events and GCBulkMovedObjectRanges
597     // events and the corresponding callbacks for profapi profilers. This method is
598     // passed a pointer to a MovedReferenceContextForEtwAndProfapi; if non-NULL it gets
599     // returned; else, a new MovedReferenceContextForEtwAndProfapi is allocated, stored
600     // in that pointer, and then returned. Callers should test for NULL, which can be
601     // returned if out of memory
602     static MovedReferenceContextForEtwAndProfapi * CreateInGCContext(LPVOID pvContext)
603     {
604         LIMITED_METHOD_CONTRACT;
605
606         _ASSERTE(pvContext != NULL);
607
608         MovedReferenceContextForEtwAndProfapi * pContext = *(MovedReferenceContextForEtwAndProfapi **) pvContext;
609         
610         // Shouldn't be called if the context was already created.  Perhaps someone made
611         // one too many BeginMovedReferences calls, or didn't have an EndMovedReferences
612         // in between?
613         _ASSERTE(pContext == NULL);
614         
615         pContext = new (nothrow) MovedReferenceContextForEtwAndProfapi;
616         *(MovedReferenceContextForEtwAndProfapi **) pvContext = pContext;
617
618         return pContext;
619     }
620
621
622     MovedReferenceContextForEtwAndProfapi() :
623         pctxProfAPI(NULL),
624         pctxEtw(NULL)
625
626     {
627         LIMITED_METHOD_CONTRACT;
628     }
629         
630     LPVOID pctxProfAPI;
631     EtwGcMovementContext * pctxEtw;
632 };
633
634
635 //---------------------------------------------------------------------------------------
636 //
637 // Called by the GC for each moved or surviving reference that it encounters. This
638 // batches the info into our context's buffer, and flushes that buffer to ETW as it fills
639 // up.
640 //
641 // Arguments:
642 //      * pbMemBlockStart - Start of moved/surviving block
643 //      * pbMemBlockEnd - Next pointer after end of moved/surviving block
644 //      * cbRelocDistance - How far did the block move? (0 for non-compacted / surviving
645 //          references; negative if moved to earlier addresses)
646 //      * profilingContext - Where our context is stored
647 //      * fCompacting - Is this a compacting GC? Used to decide whether to send the moved
648 //          or surviving event
649 //
650
651 // static
652 void ETW::GCLog::MovedReference(
653     BYTE * pbMemBlockStart,
654     BYTE * pbMemBlockEnd,
655     ptrdiff_t cbRelocDistance,
656     size_t profilingContext,
657     BOOL fCompacting,
658     BOOL fAllowProfApiNotification /* = TRUE */)
659 {
660     CONTRACTL 
661     {
662         NOTHROW;
663         GC_NOTRIGGER;
664         MODE_ANY;
665         CAN_TAKE_LOCK;  // EEToProfInterfaceImpl::AllocateMovedReferencesData takes lock
666     } 
667     CONTRACTL_END;
668
669     MovedReferenceContextForEtwAndProfapi * pCtxForEtwAndProfapi = 
670         (MovedReferenceContextForEtwAndProfapi *) profilingContext;
671     if (pCtxForEtwAndProfapi == NULL)
672     {
673         _ASSERTE(!"MovedReference() encountered a NULL profilingContext");
674         return;
675     }
676
677 #ifdef PROFILING_SUPPORTED
678     // ProfAPI
679     if (fAllowProfApiNotification)
680     {
681         BEGIN_PIN_PROFILER(CORProfilerTrackGC());
682         g_profControlBlock.pProfInterface->MovedReference(pbMemBlockStart,
683                                                           pbMemBlockEnd,
684                                                           cbRelocDistance,
685                                                           &(pCtxForEtwAndProfapi->pctxProfAPI),
686                                                           fCompacting);
687         END_PIN_PROFILER();
688     }
689 #endif // PROFILING_SUPPORTED
690
691     // ETW
692
693     if (!ShouldTrackMovementForEtw())
694         return;
695
696     EtwGcMovementContext * pContext =
697         EtwGcMovementContext::GetOrCreateInGCContext(&pCtxForEtwAndProfapi->pctxEtw);
698     if (pContext == NULL)
699         return;
700
701     if (fCompacting)
702     {
703         // Moved references
704
705         _ASSERTE(pContext->cBulkMovedObjectRanges < _countof(pContext->rgGCBulkMovedObjectRanges));
706         EventStructGCBulkMovedObjectRangesValue * pValue =
707             &pContext->rgGCBulkMovedObjectRanges[pContext->cBulkMovedObjectRanges];
708         pValue->OldRangeBase = pbMemBlockStart;
709         pValue->NewRangeBase = pbMemBlockStart + cbRelocDistance;
710         pValue->RangeLength = pbMemBlockEnd - pbMemBlockStart;
711         pContext->cBulkMovedObjectRanges++;
712
713         // If buffer is now full, empty it into ETW
714         if (pContext->cBulkMovedObjectRanges == _countof(pContext->rgGCBulkMovedObjectRanges))
715         {
716             FireEtwGCBulkMovedObjectRanges(
717                 pContext->iCurBulkMovedObjectRanges,
718                 pContext->cBulkMovedObjectRanges,
719                 GetClrInstanceId(),
720                 sizeof(pContext->rgGCBulkMovedObjectRanges[0]),
721                 &pContext->rgGCBulkMovedObjectRanges[0]);
722
723             pContext->iCurBulkMovedObjectRanges++;
724             pContext->Clear();
725         }
726     }
727     else
728     {
729         // Surviving references
730         
731         _ASSERTE(pContext->cBulkSurvivingObjectRanges < _countof(pContext->rgGCBulkSurvivingObjectRanges));
732         EventStructGCBulkSurvivingObjectRangesValue * pValue =
733             &pContext->rgGCBulkSurvivingObjectRanges[pContext->cBulkSurvivingObjectRanges];
734         pValue->RangeBase = pbMemBlockStart;
735         pValue->RangeLength = pbMemBlockEnd - pbMemBlockStart;
736         pContext->cBulkSurvivingObjectRanges++;
737
738         // If buffer is now full, empty it into ETW
739         if (pContext->cBulkSurvivingObjectRanges == _countof(pContext->rgGCBulkSurvivingObjectRanges))
740         {
741             FireEtwGCBulkSurvivingObjectRanges(
742                 pContext->iCurBulkSurvivingObjectRanges,
743                 pContext->cBulkSurvivingObjectRanges,
744                 GetClrInstanceId(),
745                 sizeof(pContext->rgGCBulkSurvivingObjectRanges[0]),
746                 &pContext->rgGCBulkSurvivingObjectRanges[0]);
747
748             pContext->iCurBulkSurvivingObjectRanges++;
749             pContext->Clear();
750         }
751     }
752 }
753
754
755 //---------------------------------------------------------------------------------------
756 //
757 // Called by the GC just before it begins enumerating plugs.  Gives us a chance to
758 // allocate our context structure, to allow us to batch plugs before firing events
759 // for them
760 //
761 // Arguments:
762 //      * pProfilingContext - Points to location on stack (in GC function) where we can
763 //         store a pointer to the context we allocate
764 //
765
766 // static
767 VOID ETW::GCLog::BeginMovedReferences(size_t * pProfilingContext)
768 {
769     LIMITED_METHOD_CONTRACT;
770
771     MovedReferenceContextForEtwAndProfapi::CreateInGCContext(LPVOID(pProfilingContext));
772 }
773
774
775 //---------------------------------------------------------------------------------------
776 //
777 // Called by the GC at the end of a heap walk to give us a place to flush any remaining
778 // buffers of data to ETW or the profapi profiler
779 //
780 // Arguments:
781 //      profilingContext - Our context we built up during the heap walk
782 //
783
784 // static
785 VOID ETW::GCLog::EndMovedReferences(size_t profilingContext, BOOL fAllowProfApiNotification /* = TRUE */)
786 {
787     CONTRACTL 
788     {
789         NOTHROW;
790         GC_NOTRIGGER;
791         MODE_ANY;
792         CAN_TAKE_LOCK;
793     } 
794     CONTRACTL_END;
795
796     MovedReferenceContextForEtwAndProfapi * pCtxForEtwAndProfapi = (MovedReferenceContextForEtwAndProfapi *) profilingContext;
797     if (pCtxForEtwAndProfapi == NULL)
798     {
799         _ASSERTE(!"EndMovedReferences() encountered a NULL profilingContext");
800         return;
801     }
802
803 #ifdef PROFILING_SUPPORTED
804     // ProfAPI
805     if (fAllowProfApiNotification)
806     {
807         BEGIN_PIN_PROFILER(CORProfilerTrackGC());
808         g_profControlBlock.pProfInterface->EndMovedReferences(&(pCtxForEtwAndProfapi->pctxProfAPI));
809         END_PIN_PROFILER();
810     }
811 #endif //PROFILING_SUPPORTED
812
813     // ETW
814     
815     if (!ShouldTrackMovementForEtw())
816         return;
817
818     // If context isn't already set up for us, then we haven't been collecting any data
819     // for ETW events.
820     EtwGcMovementContext * pContext = pCtxForEtwAndProfapi->pctxEtw;
821     if (pContext == NULL)
822         return;
823
824     // Flush any remaining moved or surviving range data
825
826     if (pContext->cBulkMovedObjectRanges > 0)
827     {
828         FireEtwGCBulkMovedObjectRanges(
829             pContext->iCurBulkMovedObjectRanges,
830             pContext->cBulkMovedObjectRanges,
831             GetClrInstanceId(),
832             sizeof(pContext->rgGCBulkMovedObjectRanges[0]),
833             &pContext->rgGCBulkMovedObjectRanges[0]);
834     }
835
836     if (pContext->cBulkSurvivingObjectRanges > 0)
837     {
838         FireEtwGCBulkSurvivingObjectRanges(
839             pContext->iCurBulkSurvivingObjectRanges,
840             pContext->cBulkSurvivingObjectRanges,
841             GetClrInstanceId(),
842             sizeof(pContext->rgGCBulkSurvivingObjectRanges[0]),
843             &pContext->rgGCBulkSurvivingObjectRanges[0]);
844     }
845
846     pCtxForEtwAndProfapi->pctxEtw = NULL;
847     delete pContext;
848 }
849
850 /***************************************************************************/
851 /* This implements the public runtime provider's GCHeapCollectKeyword.  It
852    performs a full, gen-2, blocking GC. */
853 /***************************************************************************/
854 VOID ETW::GCLog::ForceGC(LONGLONG l64ClientSequenceNumber)
855 {
856     CONTRACTL 
857     {
858         NOTHROW;
859         GC_TRIGGERS;
860         MODE_ANY;
861     } 
862     CONTRACTL_END;
863
864 #ifndef FEATURE_REDHAWK
865     if (!IsGarbageCollectorFullyInitialized())
866         return;
867 #endif // FEATURE_REDHAWK
868
869     InterlockedExchange64(&s_l64LastClientSequenceNumber, l64ClientSequenceNumber);
870
871     ForceGCForDiagnostics();
872 }
873
874 //---------------------------------------------------------------------------------------
875 //
876 // Helper to fire the GCStart event.  Figures out which version of GCStart to fire, and
877 // includes the client sequence number, if available.
878 //
879 // Arguments:
880 //      pGcInfo - ETW_GC_INFO containing details from GC about this collection
881 //
882
883 // static
884 VOID ETW::GCLog::FireGcStart(ETW_GC_INFO * pGcInfo)
885 {
886     LIMITED_METHOD_CONTRACT;
887
888     if (ETW_TRACING_CATEGORY_ENABLED(
889         MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
890         TRACE_LEVEL_INFORMATION, 
891         CLR_GC_KEYWORD))
892     {
893         // If the controller specified a client sequence number for us to log with this
894         // GCStart, then retrieve it
895         LONGLONG l64ClientSequenceNumberToLog = 0;
896         if ((s_l64LastClientSequenceNumber != 0) &&
897             (pGcInfo->GCStart.Depth == GCHeapUtilities::GetGCHeap()->GetMaxGeneration()) &&
898             (pGcInfo->GCStart.Reason == ETW_GC_INFO::GC_INDUCED))
899         {
900             l64ClientSequenceNumberToLog = InterlockedExchange64(&s_l64LastClientSequenceNumber, 0);
901         }
902
903         FireEtwGCStart_V2(pGcInfo->GCStart.Count, pGcInfo->GCStart.Depth, pGcInfo->GCStart.Reason, pGcInfo->GCStart.Type, GetClrInstanceId(), l64ClientSequenceNumberToLog);
904     }
905 }
906
907 //---------------------------------------------------------------------------------------
908 //
909 // Contains code common to profapi and ETW scenarios where the profiler wants to force
910 // the CLR to perform a GC.  The important work here is to create a managed thread for
911 // the current thread BEFORE the GC begins.  On both ETW and profapi threads, there may
912 // not yet be a managed thread object.  But some scenarios require a managed thread
913 // object be present (notably if we need to call into Jupiter during the GC).
914 //
915 // Return Value:
916 //      HRESULT indicating success or failure
917 //
918 // Assumptions:
919 //      Caller should ensure that the EE has fully started up and that the GC heap is
920 //      initialized enough to actually perform a GC
921 //
922
923 // static
924 HRESULT ETW::GCLog::ForceGCForDiagnostics()
925 {
926     CONTRACTL 
927     {
928         NOTHROW;
929         GC_TRIGGERS;
930         MODE_ANY;
931     } 
932     CONTRACTL_END;
933
934     HRESULT hr = E_FAIL;
935
936 #ifndef FEATURE_REDHAWK
937     // Caller should ensure we're past startup.
938     _ASSERTE(IsGarbageCollectorFullyInitialized());
939
940     // In immersive apps the GarbageCollect() call below will call into Jupiter,
941     // which will call back into the runtime to track references. This call
942     // chain would cause a Thread object to be created for this thread while code 
943     // higher on the stack owns the ThreadStoreLock. This will lead to asserts 
944     // since the ThreadStoreLock is non-reentrant. To avoid this we'll create 
945     // the Thread object here instead.
946     if (GetThreadNULLOk() == NULL)
947     {
948         HRESULT hr = E_FAIL;
949         SetupThreadNoThrow(&hr);
950         if (FAILED(hr))
951             return hr;
952     }
953
954     ASSERT_NO_EE_LOCKS_HELD();
955
956     EX_TRY
957     {
958         // Need to switch to cooperative mode as the thread will access managed
959         // references (through Jupiter callbacks).
960         GCX_COOP();
961 #endif // FEATURE_REDHAWK
962         
963         ForcedGCHolder forcedGCHolder;
964         
965         hr = GCHeapUtilities::GetGCHeap()->GarbageCollect(
966             -1,     // all generations should be collected
967             false,  // low_memory_p
968             collection_blocking);
969
970 #ifndef FEATURE_REDHAWK
971     }
972     EX_CATCH { }
973     EX_END_CATCH(RethrowCorruptingExceptions);
974 #endif // FEATURE_REDHAWK
975
976     return hr;
977 }
978
979
980
981
982
983
984 //---------------------------------------------------------------------------------------
985 // WalkStaticsAndCOMForETW walks both CCW/RCW objects and static variables.
986 //---------------------------------------------------------------------------------------
987
988 VOID ETW::GCLog::WalkStaticsAndCOMForETW()
989 {
990     CONTRACTL 
991     {
992         NOTHROW;
993         GC_TRIGGERS;
994     }
995     CONTRACTL_END;
996
997     EX_TRY
998     {
999         BulkTypeEventLogger typeLogger;
1000
1001         // Walk RCWs/CCWs
1002         BulkComLogger comLogger(&typeLogger);
1003         comLogger.LogAllComObjects();
1004
1005         // Walk static variables
1006         BulkStaticsLogger staticLogger(&typeLogger);
1007         staticLogger.LogAllStatics();
1008
1009         // Ensure all loggers have written all events, fire type logger last to batch events
1010         // (FireBulkComEvent or FireBulkStaticsEvent may queue up additional types).
1011         comLogger.FireBulkComEvent();
1012         staticLogger.FireBulkStaticsEvent();
1013         typeLogger.FireBulkTypeEvent();
1014     }
1015     EX_CATCH
1016     {
1017     }
1018     EX_END_CATCH(SwallowAllExceptions);
1019 }
1020
1021
1022 //---------------------------------------------------------------------------------------
1023 // BulkStaticsLogger: Batches up and logs static variable roots
1024 //---------------------------------------------------------------------------------------
1025
1026 BulkComLogger::BulkComLogger(BulkTypeEventLogger *typeLogger)
1027     : m_currRcw(0), m_currCcw(0), m_typeLogger(typeLogger), m_etwRcwData(0), m_etwCcwData(0), m_enumResult(0)
1028 {
1029     CONTRACTL
1030     {
1031         THROWS;
1032         GC_NOTRIGGER;
1033         MODE_ANY;
1034     }
1035     CONTRACTL_END;
1036
1037     m_etwRcwData = new EventRCWEntry[kMaxRcwCount];
1038     m_etwCcwData = new EventCCWEntry[kMaxCcwCount];
1039 }
1040
1041 BulkComLogger::~BulkComLogger()
1042 {
1043     CONTRACTL 
1044     {
1045         NOTHROW;
1046         GC_NOTRIGGER;
1047         MODE_ANY;
1048     }
1049     CONTRACTL_END;
1050
1051     FireBulkComEvent();
1052
1053     if (m_etwRcwData)
1054         delete [] m_etwRcwData;
1055
1056     if (m_etwCcwData)
1057         delete [] m_etwCcwData;
1058
1059     if (m_enumResult)
1060     {
1061         CCWEnumerationEntry *curr = m_enumResult;
1062         while (curr)
1063         {
1064             CCWEnumerationEntry *next = curr->Next;
1065             delete curr;
1066             curr = next;
1067         }
1068     }
1069 }
1070
1071 void BulkComLogger::FireBulkComEvent()
1072 {
1073     WRAPPER_NO_CONTRACT;
1074
1075     FlushRcw();
1076     FlushCcw();
1077 }
1078
1079 void BulkComLogger::WriteRcw(RCW *pRcw, Object *obj)
1080 {
1081     CONTRACTL 
1082     {
1083         THROWS;
1084         GC_TRIGGERS;
1085         MODE_ANY;
1086         PRECONDITION(pRcw != NULL);
1087         PRECONDITION(obj != NULL);
1088     }
1089     CONTRACTL_END;
1090
1091     _ASSERTE(m_currRcw < kMaxRcwCount);
1092
1093 #ifdef FEATURE_COMINTEROP
1094     EventRCWEntry &rcw = m_etwRcwData[m_currRcw];
1095     rcw.ObjectID = (ULONGLONG)obj;
1096     rcw.TypeID = (ULONGLONG)obj->GetTypeHandle().AsTAddr();
1097     rcw.IUnk = (ULONGLONG)pRcw->GetIUnknown_NoAddRef();
1098     rcw.VTable = (ULONGLONG)pRcw->GetVTablePtr();
1099     rcw.RefCount = pRcw->GetRefCount();
1100     rcw.Flags = 0;
1101     
1102     if (++m_currRcw >= kMaxRcwCount)
1103         FlushRcw();
1104 #endif
1105 }
1106
1107 void BulkComLogger::FlushRcw()
1108 {
1109     CONTRACTL 
1110     {
1111         NOTHROW;
1112         GC_NOTRIGGER;
1113         MODE_ANY;
1114     }
1115     CONTRACTL_END;
1116
1117     _ASSERTE(m_currRcw <= kMaxRcwCount);
1118
1119     if (m_currRcw == 0)
1120         return;
1121
1122     if (m_typeLogger)
1123     {
1124         for (int i = 0; i < m_currRcw; ++i)
1125             ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(m_typeLogger, m_etwRcwData[i].TypeID, ETW::TypeSystemLog::kTypeLogBehaviorTakeLockAndLogIfFirstTime);
1126     }
1127
1128     unsigned short instance = GetClrInstanceId();
1129
1130 #if !defined(FEATURE_PAL)
1131     EVENT_DATA_DESCRIPTOR eventData[3];
1132     EventDataDescCreate(&eventData[0], &m_currRcw, sizeof(const unsigned int));
1133     EventDataDescCreate(&eventData[1], &instance, sizeof(const unsigned short));
1134     EventDataDescCreate(&eventData[2], m_etwRcwData, sizeof(EventRCWEntry) * m_currRcw);
1135
1136     ULONG result = EventWrite(Microsoft_Windows_DotNETRuntimeHandle, &GCBulkRCW, _countof(eventData), eventData);
1137 #else
1138     ULONG result = FireEtXplatGCBulkRCW(m_currRcw, instance, sizeof(EventRCWEntry) * m_currRcw, m_etwRcwData);
1139 #endif // !defined(FEATURE_PAL)
1140
1141     _ASSERTE(result == ERROR_SUCCESS);
1142
1143     m_currRcw = 0;
1144 }
1145
1146 void BulkComLogger::WriteCcw(ComCallWrapper *pCcw, Object **handle, Object *obj)
1147 {
1148     CONTRACTL 
1149     {
1150         THROWS;
1151         GC_TRIGGERS;
1152         MODE_ANY;
1153         PRECONDITION(handle != NULL);
1154         PRECONDITION(obj != NULL);
1155     }
1156     CONTRACTL_END;
1157
1158     _ASSERTE(m_currCcw < kMaxCcwCount);
1159
1160 #ifdef FEATURE_COMINTEROP
1161     IUnknown *iUnk = NULL;
1162     int refCount = 0;
1163     ULONG jupiterRefCount = 0;
1164     ULONG flags = 0;
1165
1166     if (pCcw)
1167     {
1168         iUnk = pCcw->GetOuter();
1169         if (iUnk == NULL)
1170             iUnk = pCcw->GetBasicIP(true);
1171
1172         refCount = pCcw->GetRefCount();
1173         jupiterRefCount = pCcw->GetJupiterRefCount();
1174         
1175         if (pCcw->IsWrapperActive())
1176             flags |= EventCCWEntry::Strong;
1177
1178         if (pCcw->IsPegged())
1179             flags |= EventCCWEntry::Pegged;
1180     }
1181
1182     EventCCWEntry &ccw = m_etwCcwData[m_currCcw++];
1183     ccw.RootID = (ULONGLONG)handle;
1184     ccw.ObjectID = (ULONGLONG)obj;
1185     ccw.TypeID = (ULONGLONG)obj->GetTypeHandle().AsTAddr();
1186     ccw.IUnk = (ULONGLONG)iUnk;
1187     ccw.RefCount = refCount;
1188     ccw.JupiterRefCount = jupiterRefCount;
1189     ccw.Flags = flags;
1190     
1191     if (m_currCcw >= kMaxCcwCount)
1192         FlushCcw();
1193 #endif
1194 }
1195
1196 void BulkComLogger::FlushCcw()
1197 {
1198     CONTRACTL 
1199     {
1200         NOTHROW;
1201         GC_NOTRIGGER;
1202         MODE_ANY;
1203     }
1204     CONTRACTL_END;
1205
1206     _ASSERTE(m_currCcw <= kMaxCcwCount);
1207
1208     if (m_currCcw == 0)
1209         return;
1210
1211     if (m_typeLogger)
1212     {
1213         for (int i = 0; i < m_currCcw; ++i)
1214             ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(m_typeLogger, m_etwCcwData[i].TypeID, ETW::TypeSystemLog::kTypeLogBehaviorTakeLockAndLogIfFirstTime);
1215     }
1216
1217     unsigned short instance = GetClrInstanceId();
1218
1219 #if !defined(FEATURE_PAL)
1220     EVENT_DATA_DESCRIPTOR eventData[3];
1221     EventDataDescCreate(&eventData[0], &m_currCcw, sizeof(const unsigned int));
1222     EventDataDescCreate(&eventData[1], &instance, sizeof(const unsigned short));
1223     EventDataDescCreate(&eventData[2], m_etwCcwData, sizeof(EventCCWEntry) * m_currCcw);
1224
1225     ULONG result = EventWrite(Microsoft_Windows_DotNETRuntimeHandle, &GCBulkRootCCW, _countof(eventData), eventData);
1226 #else
1227     ULONG result = FireEtXplatGCBulkRootCCW(m_currCcw, instance, sizeof(EventCCWEntry) * m_currCcw, m_etwCcwData);
1228 #endif //!defined(FEATURE_PAL)
1229
1230     _ASSERTE(result == ERROR_SUCCESS);
1231
1232     m_currCcw = 0;
1233 }
1234
1235 void BulkComLogger::LogAllComObjects()
1236 {
1237     CONTRACTL 
1238     {
1239         THROWS;
1240         GC_TRIGGERS;
1241         MODE_ANY;
1242     }
1243     CONTRACTL_END;
1244
1245 #ifdef FEATURE_COMINTEROP
1246     SyncBlockCache *cache = SyncBlockCache::GetSyncBlockCache();
1247     if (cache == NULL)
1248         return;
1249     
1250     int count = cache->GetTableEntryCount();
1251     SyncTableEntry *table = SyncTableEntry::GetSyncTableEntry();
1252     
1253     for (int i = 0; i < count; ++i)
1254     {
1255         SyncTableEntry &entry = table[i];
1256         Object *obj = entry.m_Object.Load();
1257         if (obj && entry.m_SyncBlock)
1258         {
1259             InteropSyncBlockInfo *interop = entry.m_SyncBlock->GetInteropInfoNoCreate();
1260             if (interop)
1261             {
1262                 RCW *rcw = interop->GetRawRCW();
1263                 if (rcw)
1264                     WriteRcw(rcw, obj);
1265             }
1266         }
1267     }
1268
1269     // We need to do work in HandleWalkCallback which may trigger a GC.  We cannot do this while
1270     // enumerating the handle table.  Instead, we will build a list of RefCount handles we found
1271     // during the handle table enumeration first (m_enumResult) during this enumeration:
1272     GCHandleUtilities::GetGCHandleManager()->TraceRefCountedHandles(BulkComLogger::HandleWalkCallback, uintptr_t(this), 0);
1273
1274     // Now that we have all of the object handles, we will walk all of the handles and write the
1275     // etw events.
1276     for (CCWEnumerationEntry *curr = m_enumResult; curr; curr = curr->Next)
1277     {
1278         for (int i = 0; i < curr->Count; ++i)
1279         {
1280             Object **handle = curr->Handles[i];
1281
1282             Object *obj = NULL;
1283             if (handle == NULL || (obj = *handle) == 0)
1284                 return;
1285     
1286             ObjHeader *header = obj->GetHeader();
1287             _ASSERTE(header != NULL);
1288
1289             // We can catch the refcount handle too early where we don't have a CCW, WriteCCW
1290             // handles this case.  We still report the refcount handle without the CCW data.
1291             ComCallWrapper *ccw = NULL;
1292
1293             // Checking the index ensures that the syncblock is already created.  The
1294             // PassiveGetSyncBlock function does not check bounds, so we have to be sure
1295             // the SyncBlock was already created.
1296             int index = header->GetHeaderSyncBlockIndex();
1297             if (index > 0)
1298             {
1299                 SyncBlock *syncBlk = header->PassiveGetSyncBlock();
1300                 InteropSyncBlockInfo *interop = syncBlk->GetInteropInfoNoCreate();
1301                 if (interop)
1302                     ccw = interop->GetCCW();
1303             }
1304     
1305             WriteCcw(ccw, handle, obj);
1306         }
1307     }
1308
1309 #endif
1310
1311 }
1312
1313 void BulkComLogger::HandleWalkCallback(Object **handle, uintptr_t *pExtraInfo, uintptr_t param1, uintptr_t param2)
1314 {
1315     CONTRACTL 
1316     {
1317         THROWS;
1318         GC_NOTRIGGER;
1319         MODE_ANY;
1320         PRECONDITION(param1 != NULL);   // Should be the "this" pointer for BulkComLogger.
1321         PRECONDITION(param2 == 0);      // This is set by Ref_TraceRefCountHandles.
1322     }
1323     CONTRACTL_END;
1324
1325     // Simple sanity check to ensure the parameters are what we expect them to be.
1326     _ASSERTE(param2 == 0);
1327     
1328     if (handle != NULL)
1329         ((BulkComLogger*)param1)->AddCcwHandle(handle);
1330 }
1331
1332
1333
1334 // Used during CCW enumeration to keep track of all object handles which point to a CCW.
1335 void BulkComLogger::AddCcwHandle(Object **handle)
1336 {
1337     CONTRACTL 
1338     {
1339         THROWS;
1340         GC_NOTRIGGER;
1341         MODE_ANY;
1342         PRECONDITION(handle != NULL);
1343     }
1344     CONTRACTL_END;
1345
1346     if (m_enumResult == NULL)
1347         m_enumResult = new CCWEnumerationEntry;
1348
1349     CCWEnumerationEntry *curr = m_enumResult;
1350     while (curr->Next)
1351         curr = curr->Next;
1352
1353     if (curr->Count == _countof(curr->Handles))
1354     {
1355         curr->Next = new CCWEnumerationEntry;
1356         curr = curr->Next;
1357     }
1358
1359     curr->Handles[curr->Count++] = handle;
1360 }
1361     
1362
1363
1364
1365 //---------------------------------------------------------------------------------------
1366 // BulkStaticsLogger: Batches up and logs static variable roots
1367 //---------------------------------------------------------------------------------------
1368
1369
1370
1371 #include "domainfile.h"
1372
1373 BulkStaticsLogger::BulkStaticsLogger(BulkTypeEventLogger *typeLogger)
1374     : m_buffer(0), m_used(0), m_count(0), m_domain(0), m_typeLogger(typeLogger)
1375 {
1376     CONTRACTL
1377     {
1378         THROWS;
1379         GC_NOTRIGGER;
1380         MODE_ANY;
1381     }
1382     CONTRACTL_END;
1383
1384     m_buffer = new BYTE[kMaxBytesValues];
1385 }
1386
1387 BulkStaticsLogger::~BulkStaticsLogger()
1388 {
1389     CONTRACTL 
1390     {
1391         NOTHROW;
1392         GC_NOTRIGGER;
1393         MODE_ANY;
1394     }
1395     CONTRACTL_END;
1396
1397     if (m_used > 0)
1398         FireBulkStaticsEvent();
1399
1400     if (m_buffer)
1401         delete[] m_buffer;
1402 }
1403
1404 void BulkStaticsLogger::FireBulkStaticsEvent()
1405 {
1406     CONTRACTL
1407     {
1408         NOTHROW;
1409         GC_NOTRIGGER;
1410         MODE_ANY;
1411     }
1412     CONTRACTL_END;
1413
1414     if (m_used <= 0 || m_count <= 0)
1415         return;
1416
1417     _ASSERTE(m_domain != NULL);
1418
1419     unsigned short instance = GetClrInstanceId();
1420     unsigned __int64 appDomain = (unsigned __int64)m_domain;
1421
1422 #if !defined(FEATURE_PAL)
1423     EVENT_DATA_DESCRIPTOR eventData[4];
1424     EventDataDescCreate(&eventData[0], &m_count, sizeof(const unsigned int)  );
1425     EventDataDescCreate(&eventData[1], &appDomain, sizeof(unsigned __int64)  );
1426     EventDataDescCreate(&eventData[2], &instance, sizeof(const unsigned short)  );
1427     EventDataDescCreate(&eventData[3], m_buffer, m_used);
1428
1429     ULONG result = EventWrite(Microsoft_Windows_DotNETRuntimeHandle, &GCBulkRootStaticVar, _countof(eventData), eventData);
1430 #else
1431     ULONG result = FireEtXplatGCBulkRootStaticVar(m_count, appDomain, instance, m_used, m_buffer);
1432 #endif //!defined(FEATURE_PAL)
1433
1434     _ASSERTE(result == ERROR_SUCCESS);
1435
1436     m_used = 0;
1437     m_count = 0;
1438 }
1439
1440 void BulkStaticsLogger::WriteEntry(AppDomain *domain, Object **address, Object *obj, FieldDesc *fieldDesc)
1441 {
1442     CONTRACTL
1443     {
1444         NOTHROW;
1445         GC_NOTRIGGER;
1446         MODE_ANY;
1447         PRECONDITION(domain != NULL);
1448         PRECONDITION(address != NULL);
1449         PRECONDITION(obj != NULL);
1450         PRECONDITION(fieldDesc != NULL);
1451     }
1452     CONTRACTL_END;
1453
1454     // Each bulk statics event is for one AppDomain.  If we are now inspecting a new domain,
1455     // we need to flush the built up events now.
1456     if (m_domain != domain)
1457     {
1458         if (m_domain != NULL)
1459             FireBulkStaticsEvent();
1460
1461         m_domain = domain;
1462     }
1463     
1464     ULONGLONG th = (ULONGLONG)obj->GetTypeHandle().AsTAddr();
1465     ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(m_typeLogger, th, ETW::TypeSystemLog::kTypeLogBehaviorTakeLockAndLogIfFirstTime);
1466
1467     // We should have at least 512 characters remaining in the buffer here.
1468     int remaining = kMaxBytesValues - m_used;
1469     _ASSERTE(kMaxBytesValues - m_used > 512);
1470
1471     int len = EventStaticEntry::WriteEntry(m_buffer + m_used, remaining, (ULONGLONG)address,
1472                                            (ULONGLONG)obj, th, 0, fieldDesc);
1473
1474     // 512 bytes was not enough buffer?  This shouldn't happen, so we'll skip emitting the
1475     // event on error.
1476     if (len > 0)
1477     {
1478         m_used += len;
1479         m_count++;
1480     }
1481
1482     // When we are close to running out of buffer, emit the event.
1483     if (kMaxBytesValues - m_used < 512)
1484         FireBulkStaticsEvent();
1485 }
1486
1487 void BulkStaticsLogger::LogAllStatics()
1488 {
1489     CONTRACTL
1490     {
1491         NOTHROW;
1492         GC_NOTRIGGER;
1493         MODE_ANY;
1494     }
1495     CONTRACTL_END;
1496
1497     // Enumerate only active app domains (first parameter).  We use the unsafe
1498     // iterator here because this method is called under the threadstore lock
1499     // and it's safe to use while the runtime is suspended.
1500     UnsafeAppDomainIterator appIter(TRUE);
1501     appIter.Init();
1502     while (appIter.Next())
1503     {
1504         AppDomain *domain = appIter.GetDomain();
1505
1506         AppDomain::AssemblyIterator assemblyIter = domain->IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded|kIncludeExecution));
1507         CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1508         while (assemblyIter.Next(pDomainAssembly.This()))
1509         {
1510             // Make sure the assembly is loaded.
1511             if (!pDomainAssembly->IsLoaded())
1512                 continue;
1513                 
1514             CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetAssembly();
1515             DomainModuleIterator modIter = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1516             
1517             while (modIter.Next())
1518             {
1519                 // Get the domain module from the module/appdomain pair.
1520                 Module *module = modIter.GetModule();
1521                 if (module == NULL)
1522                     continue;
1523
1524                 DomainFile *domainFile = module->FindDomainFile(domain);
1525                 if (domainFile == NULL)
1526                     continue;
1527
1528                 // Ensure the module has fully loaded.
1529                 if (!domainFile->IsActive())
1530                     continue;
1531
1532                 DomainLocalModule *domainModule = module->GetDomainLocalModule(domain);
1533                 if (domainModule == NULL)
1534                     continue;
1535
1536                 // Now iterate all types with 
1537                 LookupMap<PTR_MethodTable>::Iterator mtIter = module->EnumerateTypeDefs();
1538                 while (mtIter.Next())
1539                 {
1540                     // I don't think mt can be null here, but the dac does a null check...
1541                     // IsFullyLoaded should be equivalent to 'GetLoadLevel() == CLASS_LOADED'
1542                     MethodTable *mt = mtIter.GetElement();
1543                     if (mt == NULL || !mt->IsFullyLoaded())
1544                         continue;
1545
1546                     EEClass *cls = mt->GetClass();
1547                     _ASSERTE(cls != NULL);
1548                     
1549                     if (cls->GetNumStaticFields() <= 0)
1550                         continue;
1551                         
1552                     ApproxFieldDescIterator fieldIter(mt, ApproxFieldDescIterator::STATIC_FIELDS);
1553                     for (FieldDesc *field = fieldIter.Next(); field != NULL; field = fieldIter.Next())
1554                     {
1555                         // Don't want thread local
1556                         _ASSERTE(field->IsStatic());
1557                         if (field->IsSpecialStatic() || field->IsEnCNew())
1558                             continue;
1559                             
1560                         // Static valuetype values are boxed.
1561                         CorElementType fieldType = field->GetFieldType();
1562                         if (fieldType != ELEMENT_TYPE_CLASS && fieldType != ELEMENT_TYPE_VALUETYPE)
1563                             continue;
1564                             
1565                         BYTE *base = field->GetBaseInDomainLocalModule(domainModule);
1566                         if (base == NULL)
1567                             continue;
1568
1569                         Object **address = (Object**)field->GetStaticAddressHandle(base);
1570                         Object *obj = NULL;
1571                         if (address == NULL || ((obj = *address) == NULL))
1572                             continue;
1573                         
1574                         WriteEntry(domain, address, *address, field);
1575                     } // foreach static field
1576                 }
1577             } // foreach domain module
1578         } // foreach domain assembly
1579     } // foreach AppDomain
1580 } // BulkStaticsLogger::LogAllStatics
1581
1582
1583
1584 //---------------------------------------------------------------------------------------
1585 // BulkTypeValue / BulkTypeEventLogger: These take care of batching up types so they can
1586 // be logged via ETW in bulk
1587 //---------------------------------------------------------------------------------------
1588
1589 BulkTypeValue::BulkTypeValue() : cTypeParameters(0)
1590 #ifdef FEATURE_REDHAWK
1591 , ullSingleTypeParameter(0)
1592 #else // FEATURE_REDHAWK
1593 , sName()
1594 #endif // FEATURE_REDHAWK
1595 , rgTypeParameters()
1596 {
1597     LIMITED_METHOD_CONTRACT;
1598     ZeroMemory(&fixedSizedData, sizeof(fixedSizedData));
1599 }
1600
1601 //---------------------------------------------------------------------------------------
1602 //
1603 // Clears a BulkTypeValue so it can be reused after the buffer is flushed to ETW
1604 //
1605
1606 void BulkTypeValue::Clear()
1607 {
1608     CONTRACTL 
1609     {
1610         THROWS;
1611         GC_NOTRIGGER;
1612         MODE_ANY;
1613     } 
1614     CONTRACTL_END;
1615
1616     ZeroMemory(&fixedSizedData, sizeof(fixedSizedData));
1617     cTypeParameters = 0;
1618 #ifdef FEATURE_REDHAWK
1619     ullSingleTypeParameter = 0;
1620     rgTypeParameters.Release();
1621 #else // FEATURE_REDHAWK
1622     sName.Clear();
1623     rgTypeParameters.Clear();
1624 #endif // FEATURE_REDHAWK
1625 }
1626
1627 //---------------------------------------------------------------------------------------
1628 //
1629 // Fire an ETW event for all the types we batched so far, and then reset our state
1630 // so we can start batching new types at the beginning of the array.
1631 //
1632 //
1633
1634 void BulkTypeEventLogger::FireBulkTypeEvent()
1635 {
1636     LIMITED_METHOD_CONTRACT;
1637
1638     if (m_nBulkTypeValueCount == 0)
1639     {
1640         // No types were batched up, so nothing to send
1641         return;
1642     }
1643     UINT16 nClrInstanceID = GetClrInstanceId();
1644
1645     if(m_pBulkTypeEventBuffer == NULL)
1646     {
1647         // The buffer could not be allocated when this object was created, so bail.
1648         return;
1649     }
1650
1651     UINT iSize = 0;
1652     
1653     for (int iTypeData = 0; iTypeData < m_nBulkTypeValueCount; iTypeData++)
1654     {
1655         BulkTypeValue& target = m_rgBulkTypeValues[iTypeData];
1656         
1657         // Do fixed-size data as one bulk copy
1658         memcpy(
1659                 m_pBulkTypeEventBuffer + iSize,
1660                 &(target.fixedSizedData),
1661                 sizeof(target.fixedSizedData));
1662         iSize += sizeof(target.fixedSizedData);
1663
1664         // Do var-sized data individually per field
1665
1666         LPCWSTR wszName = target.sName.GetUnicode();
1667         if (wszName == NULL)
1668         {
1669             m_pBulkTypeEventBuffer[iSize++] = 0;
1670             m_pBulkTypeEventBuffer[iSize++] = 0;
1671         }
1672         else
1673         {
1674             UINT nameSize = (target.sName.GetCount() + 1) * sizeof(WCHAR);
1675             memcpy(m_pBulkTypeEventBuffer + iSize, wszName, nameSize);
1676             iSize += nameSize;
1677         }
1678
1679         // Type parameter count
1680         ULONG params = target.rgTypeParameters.GetCount();
1681         
1682         ULONG *ptrInt = (ULONG*)(m_pBulkTypeEventBuffer + iSize);
1683         *ptrInt = params;
1684         iSize += 4;
1685         
1686         target.cTypeParameters = params;
1687
1688         // Type parameter array
1689         if (target.cTypeParameters > 0)
1690         {
1691             memcpy(m_pBulkTypeEventBuffer + iSize, target.rgTypeParameters.GetElements(), sizeof(ULONGLONG) * target.cTypeParameters);
1692             iSize += sizeof(ULONGLONG) * target.cTypeParameters;
1693         }
1694     }
1695
1696     FireEtwBulkType(m_nBulkTypeValueCount, GetClrInstanceId(), iSize, m_pBulkTypeEventBuffer);
1697
1698     // Reset state
1699     m_nBulkTypeValueCount = 0;
1700     m_nBulkTypeValueByteCount = 0;
1701 }
1702
1703 #ifndef FEATURE_REDHAWK
1704
1705 //---------------------------------------------------------------------------------------
1706 //
1707 // Batches a single type into the array, flushing the array to ETW if it fills up. Most
1708 // interaction with the type system (to analyze the type) is done here. This does not
1709 // recursively batch up any parameter types (for arrays or generics), but does add their
1710 // TypeHandles to the rgTypeParameters array. LogTypeAndParameters is responsible for
1711 // initiating any recursive calls to deal with type parameters.
1712 //
1713 // Arguments:
1714 //      th - TypeHandle to batch
1715 //
1716 // Return Value:
1717 //      Index into array of where this type got batched. -1 if there was a failure.
1718 //
1719
1720 int BulkTypeEventLogger::LogSingleType(TypeHandle th)
1721 {
1722     CONTRACTL
1723     {
1724         NOTHROW;
1725         GC_NOTRIGGER;
1726         MODE_ANY;
1727         CAN_TAKE_LOCK;  // some of the type system stuff can take locks
1728     } 
1729     CONTRACTL_END;
1730
1731     // If there's no room for another type, flush what we've got
1732     if (m_nBulkTypeValueCount == _countof(m_rgBulkTypeValues))
1733     {
1734         FireBulkTypeEvent();
1735     }
1736     
1737     _ASSERTE(m_nBulkTypeValueCount < _countof(m_rgBulkTypeValues));
1738
1739     if (!th.IsTypeDesc() && th.GetMethodTable()->IsArray())
1740     {
1741         _ASSERTE(!"BulkTypeEventLogger::LogSingleType called with MethodTable array");
1742         return -1;
1743     }
1744
1745     BulkTypeValue * pVal = &m_rgBulkTypeValues[m_nBulkTypeValueCount];
1746     
1747     // Clear out pVal before filling it out (array elements can get reused if there
1748     // are enough types that we need to flush to multiple events).  Clearing the
1749     // contained SBuffer can throw, so deal with exceptions
1750     BOOL fSucceeded = FALSE;
1751     EX_TRY
1752     {
1753         pVal->Clear();
1754         fSucceeded = TRUE;
1755     }
1756     EX_CATCH
1757     {
1758         fSucceeded = FALSE;
1759     }
1760     EX_END_CATCH(RethrowCorruptingExceptions);
1761     if (!fSucceeded)
1762         return -1;      
1763
1764     pVal->fixedSizedData.TypeID = (ULONGLONG) th.AsTAddr();
1765     pVal->fixedSizedData.ModuleID = (ULONGLONG) (TADDR) th.GetModule();
1766     pVal->fixedSizedData.TypeNameID = (th.GetMethodTable() == NULL) ? 0 : th.GetCl();
1767     pVal->fixedSizedData.Flags = 0;
1768     pVal->fixedSizedData.CorElementType = (BYTE) th.GetInternalCorElementType();
1769
1770     if (th.IsArray())
1771     {
1772         // Normal typedesc array
1773         pVal->fixedSizedData.Flags |= kEtwTypeFlagsArray;
1774
1775         // Fetch TypeHandle of array elements
1776         fSucceeded = FALSE;
1777         EX_TRY
1778         {
1779             pVal->rgTypeParameters.Append((ULONGLONG) th.AsArray()->GetArrayElementTypeHandle().AsTAddr());
1780             fSucceeded = TRUE;
1781         }
1782         EX_CATCH
1783         {
1784             fSucceeded = FALSE;
1785         }
1786         EX_END_CATCH(RethrowCorruptingExceptions);
1787         if (!fSucceeded)
1788             return -1;      
1789     }
1790     else if (th.IsTypeDesc())
1791     {
1792         // Non-array Typedescs
1793         PTR_TypeDesc pTypeDesc = th.AsTypeDesc();
1794         if (pTypeDesc->HasTypeParam())
1795         {
1796             fSucceeded = FALSE;
1797             EX_TRY
1798             {
1799                 pVal->rgTypeParameters.Append((ULONGLONG) pTypeDesc->GetTypeParam().AsTAddr());
1800                 fSucceeded = TRUE;
1801             }
1802             EX_CATCH
1803             {
1804                 fSucceeded = FALSE;
1805             }
1806             EX_END_CATCH(RethrowCorruptingExceptions);
1807             if (!fSucceeded)
1808                 return -1;      
1809         }
1810     }
1811     else
1812     {
1813         // Non-array MethodTable
1814
1815         PTR_MethodTable pMT = th.AsMethodTable();
1816
1817         // Make CorElementType more specific if this is a string MT
1818         if (pMT->IsString())
1819         {
1820             pVal->fixedSizedData.CorElementType = ELEMENT_TYPE_STRING;
1821         }
1822         else if (pMT->IsObjectClass())
1823         {
1824             pVal->fixedSizedData.CorElementType = ELEMENT_TYPE_OBJECT;
1825         }
1826
1827         // Generic arguments
1828         DWORD cTypeParameters = pMT->GetNumGenericArgs();
1829         if (cTypeParameters > 0)
1830         {
1831             Instantiation inst = pMT->GetInstantiation();
1832             fSucceeded = FALSE;
1833             EX_TRY
1834             {
1835                 for (DWORD i=0; i < cTypeParameters; i++)
1836                 {
1837                     pVal->rgTypeParameters.Append((ULONGLONG) inst[i].AsTAddr());
1838                 }
1839                 fSucceeded = TRUE;
1840             }
1841             EX_CATCH
1842             {
1843                 fSucceeded = FALSE;
1844             }
1845             EX_END_CATCH(RethrowCorruptingExceptions);
1846             if (!fSucceeded)
1847                 return -1;      
1848         }
1849
1850         if (pMT->HasFinalizer())
1851         {
1852             pVal->fixedSizedData.Flags |= kEtwTypeFlagsFinalizable;
1853         }
1854         if (pMT->IsDelegate())
1855         {
1856             pVal->fixedSizedData.Flags |= kEtwTypeFlagsDelegate;
1857         }
1858         if (pMT->IsComObjectType())
1859         {
1860             pVal->fixedSizedData.Flags |= kEtwTypeFlagsExternallyImplementedCOMObject;
1861         }
1862     }
1863
1864     // If the profiler wants it, construct a name.  Always normalize the string (even if
1865     // type names are not requested) so that calls to sName.GetCount() can't throw
1866     EX_TRY
1867     {
1868         if (ETW_TRACING_CATEGORY_ENABLED(
1869             MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
1870             TRACE_LEVEL_INFORMATION, 
1871             CLR_GCHEAPANDTYPENAMES_KEYWORD))
1872         {
1873             th.GetName(pVal->sName);
1874         }
1875         pVal->sName.Normalize();
1876     }
1877     EX_CATCH
1878     {
1879         // If this failed, the name remains empty, which is ok; the event just
1880         // won't have a name in it.
1881         pVal->sName.Clear();
1882     }
1883     EX_END_CATCH(RethrowCorruptingExceptions);
1884
1885     // Now that we know the full size of this type's data, see if it fits in our
1886     // batch or whether we need to flush
1887
1888     int cbVal = pVal->GetByteCountInEvent();
1889     if (cbVal > kMaxBytesTypeValues)
1890     {
1891         // This type is apparently so huge, it's too big to squeeze into an event, even
1892         // if it were the only type batched in the whole event.  Bail
1893         _ASSERTE(!"Type too big to log via ETW");
1894         return -1;
1895     }
1896
1897     if (m_nBulkTypeValueByteCount + cbVal > kMaxBytesTypeValues)
1898     {
1899         // Although this type fits into the array, its size is so big that the entire
1900         // array can't be logged via ETW. So flush the array, and start over by
1901         // calling ourselves--this refetches the type info and puts it at the
1902         // beginning of the array.  Since we know this type is small enough to be
1903         // batched into an event on its own, this recursive call will not try to
1904         // call itself again.
1905         FireBulkTypeEvent();
1906         return LogSingleType(th);
1907     }
1908
1909     // The type fits into the batch, so update our state
1910     m_nBulkTypeValueCount++;
1911     m_nBulkTypeValueByteCount += cbVal;
1912     return m_nBulkTypeValueCount - 1;       // Index of type we just added
1913 }
1914
1915 //---------------------------------------------------------------------------------------
1916 //
1917 // High-level method to batch a type and (recursively) its type parameters, flushing to
1918 // ETW as needed.  This is called by (static)
1919 // ETW::TypeSystemLog::LogTypeAndParametersIfNecessary, which is what clients use to log
1920 // type events
1921 //
1922 // Arguments:
1923 //      * thAsAddr - Type to batch
1924 //      * typeLogBehavior - Reminder of whether the type system log lock is held
1925 //          (useful if we need to recurively call back into TypeSystemLog), and whether
1926 //          we even care to check if the type was already logged
1927 //
1928
1929 void BulkTypeEventLogger::LogTypeAndParameters(ULONGLONG thAsAddr, ETW::TypeSystemLog::TypeLogBehavior typeLogBehavior)
1930 {
1931     CONTRACTL
1932     {
1933         NOTHROW;
1934         GC_NOTRIGGER;
1935         MODE_ANY;
1936         CAN_TAKE_LOCK;  // LogSingleType can take locks
1937     } 
1938     CONTRACTL_END;
1939
1940     TypeHandle th = TypeHandle::FromTAddr((TADDR) thAsAddr);
1941
1942     // Batch up this type.  This grabs useful info about the type, including any
1943     // type parameters it may have, and sticks it in m_rgBulkTypeValues
1944     int iBulkTypeEventData = LogSingleType(th);
1945     if (iBulkTypeEventData == -1)
1946     {
1947         // There was a failure trying to log the type, so don't bother with its type
1948         // parameters
1949         return;
1950     }
1951
1952     // Look at the type info we just batched, so we can get the type parameters
1953     BulkTypeValue * pVal = &m_rgBulkTypeValues[iBulkTypeEventData];
1954
1955     // We're about to recursively call ourselves for the type parameters, so make a
1956     // local copy of their type handles first (else, as we log them we could flush
1957     // and clear out m_rgBulkTypeValues, thus trashing pVal)
1958     
1959     StackSArray<ULONGLONG> rgTypeParameters;
1960     DWORD cParams = pVal->rgTypeParameters.GetCount();
1961
1962     BOOL fSucceeded = FALSE;
1963     EX_TRY
1964     {
1965         for (COUNT_T i = 0; i < cParams; i++)
1966         {
1967             rgTypeParameters.Append(pVal->rgTypeParameters[i]);
1968         }
1969         fSucceeded = TRUE;
1970     }
1971     EX_CATCH
1972     {
1973         fSucceeded = FALSE;
1974     }
1975     EX_END_CATCH(RethrowCorruptingExceptions);
1976     if (!fSucceeded)
1977         return;      
1978
1979     // Before we recurse, adjust the special-cased type-log behavior that allows a
1980     // top-level type to be logged without lookup, but still requires lookups to avoid
1981     // dupes of type parameters
1982     if (typeLogBehavior == ETW::TypeSystemLog::kTypeLogBehaviorAlwaysLogTopLevelType)
1983         typeLogBehavior = ETW::TypeSystemLog::kTypeLogBehaviorTakeLockAndLogIfFirstTime;
1984
1985     // Recursively log any referenced parameter types
1986     for (COUNT_T i=0; i < cParams; i++)
1987     {
1988         ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(this, rgTypeParameters[i], typeLogBehavior);
1989     }
1990 }
1991
1992 #endif // FEATURE_REDHAWK
1993
1994 // Holds state that batches of roots, nodes, edges, and types as the GC walks the heap
1995 // at the end of a collection.
1996 class EtwGcHeapDumpContext
1997 {
1998 public:
1999     // An instance of EtwGcHeapDumpContext is dynamically allocated and stored inside of
2000     // ProfilingScanContext and ProfilerWalkHeapContext, which are context structures
2001     // that the GC heap walker sends back to the callbacks. This method is passed a
2002     // pointer to ProfilingScanContext::pvEtwContext or
2003     // ProfilerWalkHeapContext::pvEtwContext; if non-NULL it gets returned; else, a new
2004     // EtwGcHeapDumpContext is allocated, stored in that pointer, and then returned. 
2005     // Callers should test for NULL, which can be returned if out of memory
2006     static EtwGcHeapDumpContext * GetOrCreateInGCContext(LPVOID * ppvEtwContext)
2007     {
2008         LIMITED_METHOD_CONTRACT;
2009
2010         _ASSERTE(ppvEtwContext != NULL);
2011
2012         EtwGcHeapDumpContext * pContext = (EtwGcHeapDumpContext *) *ppvEtwContext;
2013         if (pContext == NULL)
2014         {
2015             pContext = new (nothrow) EtwGcHeapDumpContext;
2016             *ppvEtwContext = pContext;
2017         }
2018         return pContext;
2019     }
2020
2021     EtwGcHeapDumpContext() :
2022         iCurBulkRootEdge(0),
2023         iCurBulkRootConditionalWeakTableElementEdge(0),
2024         iCurBulkNodeEvent(0),
2025         iCurBulkEdgeEvent(0),
2026         bulkTypeEventLogger()
2027     {
2028         LIMITED_METHOD_CONTRACT;
2029         ClearRootEdges();
2030         ClearRootConditionalWeakTableElementEdges();
2031         ClearNodes();
2032         ClearEdges();
2033     }
2034
2035     // These helpers clear the individual buffers, for use after a flush and on
2036     // construction.  They intentionally leave the indices (iCur*) alone, since they
2037     // persist across flushes within a GC
2038
2039     void ClearRootEdges()
2040     {
2041         LIMITED_METHOD_CONTRACT;
2042         cGcBulkRootEdges = 0;
2043         ZeroMemory(rgGcBulkRootEdges, sizeof(rgGcBulkRootEdges));
2044     }
2045
2046     void ClearRootConditionalWeakTableElementEdges()
2047     {
2048         LIMITED_METHOD_CONTRACT;
2049         cGCBulkRootConditionalWeakTableElementEdges = 0;
2050         ZeroMemory(rgGCBulkRootConditionalWeakTableElementEdges, sizeof(rgGCBulkRootConditionalWeakTableElementEdges));
2051     }
2052
2053     void ClearNodes()
2054     {
2055         LIMITED_METHOD_CONTRACT;
2056         cGcBulkNodeValues = 0;
2057         ZeroMemory(rgGcBulkNodeValues, sizeof(rgGcBulkNodeValues));
2058     }
2059
2060     void ClearEdges()
2061     {
2062         LIMITED_METHOD_CONTRACT;
2063         cGcBulkEdgeValues = 0;
2064         ZeroMemory(rgGcBulkEdgeValues, sizeof(rgGcBulkEdgeValues));
2065     }
2066
2067     //---------------------------------------------------------------------------------------
2068     // GCBulkRootEdge
2069     // 
2070     // A "root edge" is the relationship between a source "GCRootID" (i.e., stack
2071     // variable, handle, static, etc.) and the target "RootedNodeAddress" (the managed
2072     // object that gets rooted).
2073     //
2074     //---------------------------------------------------------------------------------------
2075
2076     // Sequence number for each GCBulkRootEdge event
2077     UINT iCurBulkRootEdge;
2078
2079     // Number of root edges currently filled out in rgGcBulkRootEdges array
2080     UINT cGcBulkRootEdges;
2081
2082     // Struct array containing the primary data for each GCBulkRootEdge event.  Fix the size so
2083     // the total event stays well below the 64K
2084     // limit (leaving lots of room for non-struct fields that come before the root edge data)
2085     EventStructGCBulkRootEdgeValue rgGcBulkRootEdges[(cbMaxEtwEvent - 0x100) / sizeof(EventStructGCBulkRootEdgeValue)];
2086
2087
2088     //---------------------------------------------------------------------------------------
2089     // GCBulkRootConditionalWeakTableElementEdge
2090     // 
2091     // These describe dependent handles, which simulate an edge connecting a key NodeID
2092     // to a value NodeID.
2093     //
2094     //---------------------------------------------------------------------------------------
2095
2096     // Sequence number for each GCBulkRootConditionalWeakTableElementEdge event
2097     UINT iCurBulkRootConditionalWeakTableElementEdge;
2098
2099     // Number of root edges currently filled out in rgGCBulkRootConditionalWeakTableElementEdges array
2100     UINT cGCBulkRootConditionalWeakTableElementEdges;
2101
2102     // Struct array containing the primary data for each GCBulkRootConditionalWeakTableElementEdge event.  Fix the size so
2103     // the total event stays well below the 64K
2104     // limit (leaving lots of room for non-struct fields that come before the root edge data)
2105     EventStructGCBulkRootConditionalWeakTableElementEdgeValue rgGCBulkRootConditionalWeakTableElementEdges
2106         [(cbMaxEtwEvent - 0x100) / sizeof(EventStructGCBulkRootConditionalWeakTableElementEdgeValue)];
2107
2108     //---------------------------------------------------------------------------------------
2109     // GCBulkNode
2110     // 
2111     // A "node" is ANY managed object sitting on the heap, including RootedNodeAddresses
2112     // as well as leaf nodes.
2113     //
2114     //---------------------------------------------------------------------------------------
2115
2116     // Sequence number for each GCBulkNode event
2117     UINT iCurBulkNodeEvent;
2118
2119     // Number of nodes currently filled out in rgGcBulkNodeValues array
2120     UINT cGcBulkNodeValues;
2121
2122     // Struct array containing the primary data for each GCBulkNode event.  Fix the size so
2123     // the total event stays well below the 64K
2124     // limit (leaving lots of room for non-struct fields that come before the node data)
2125     EventStructGCBulkNodeValue rgGcBulkNodeValues[(cbMaxEtwEvent - 0x100) / sizeof(EventStructGCBulkNodeValue)];
2126
2127     //---------------------------------------------------------------------------------------
2128     // GCBulkEdge
2129     // 
2130     // An "edge" is the relationship between a source node and its referenced target
2131     // node. Edges are reported in bulk, separately from Nodes, but it is expected that
2132     // the consumer read the Node and Edge streams together. One takes the first node
2133     // from the Node stream, and then reads EdgeCount entries in the Edge stream, telling
2134     // you all of that Node's targets. Then, one takes the next node in the Node stream,
2135     // and reads the next entries in the Edge stream (using this Node's EdgeCount to
2136     // determine how many) to find all of its targets. This continues on until the Node
2137     // and Edge streams have been fully read.
2138     // 
2139     // GCBulkRootEdges are not duplicated in the GCBulkEdge events. GCBulkEdge events
2140     // begin at the GCBulkRootEdge.RootedNodeAddress and move forward.
2141     // 
2142     //---------------------------------------------------------------------------------------
2143
2144     // Sequence number for each GCBulkEdge event
2145     UINT iCurBulkEdgeEvent;
2146
2147     // Number of nodes currently filled out in rgGcBulkEdgeValues array
2148     UINT cGcBulkEdgeValues;
2149
2150     // Struct array containing the primary data for each GCBulkEdge event.  Fix the size so
2151     // the total event stays well below the 64K
2152     // limit (leaving lots of room for non-struct fields that come before the edge data)
2153     EventStructGCBulkEdgeValue rgGcBulkEdgeValues[(cbMaxEtwEvent - 0x100) / sizeof(EventStructGCBulkEdgeValue)];
2154
2155
2156     //---------------------------------------------------------------------------------------
2157     // BulkType
2158     // 
2159     // Types are a bit more complicated to batch up, since their data is of varying
2160     // size.  BulkTypeEventLogger takes care of the pesky details for us
2161     //---------------------------------------------------------------------------------------
2162     
2163     BulkTypeEventLogger bulkTypeEventLogger;
2164 };
2165
2166
2167
2168 //---------------------------------------------------------------------------------------
2169 //
2170 // Called during a heap walk for each root reference encountered.  Batches up the root in
2171 // the ETW context
2172 //
2173 // Arguments:
2174 //      * pvHandle - If the root is a handle, this points to the handle
2175 //      * pRootedNode - Points to object that is rooted
2176 //      * pSecondaryNodeForDependentHandle - For dependent handles, this is the
2177 //          secondary object
2178 //      * fDependentHandle - nonzero iff this is for a dependent handle
2179 //      * profilingScanContext - The shared profapi/etw context built up during the heap walk.
2180 //      * dwGCFlags - Bitmask of "GC_"-style flags set by GC
2181 //      * rootFlags - Bitmask of EtwGCRootFlags describing the root
2182 //
2183
2184 // static
2185 VOID ETW::GCLog::RootReference(
2186     LPVOID pvHandle,
2187     Object * pRootedNode,
2188     Object * pSecondaryNodeForDependentHandle,
2189     BOOL fDependentHandle,
2190     ProfilingScanContext * profilingScanContext,
2191     DWORD dwGCFlags,
2192     DWORD rootFlags)
2193 {
2194     LIMITED_METHOD_CONTRACT;
2195
2196     EtwGcHeapDumpContext * pContext =
2197         EtwGcHeapDumpContext::GetOrCreateInGCContext(&profilingScanContext->pvEtwContext);
2198     if (pContext == NULL)
2199         return;
2200
2201     // Determine root kind, root ID, and handle-specific flags
2202     LPVOID pvRootID = NULL;
2203     BYTE nRootKind = (BYTE) profilingScanContext->dwEtwRootKind;
2204     switch (nRootKind)
2205     {
2206     case kEtwGCRootKindStack:
2207 #if !defined (FEATURE_REDHAWK) && (defined(GC_PROFILING) || defined (DACCESS_COMPILE))
2208         pvRootID = profilingScanContext->pMD;
2209 #endif // !defined (FEATURE_REDHAWK) && (defined(GC_PROFILING) || defined (DACCESS_COMPILE))
2210         break;
2211
2212     case kEtwGCRootKindHandle:
2213         pvRootID = pvHandle;
2214         break;
2215
2216     case kEtwGCRootKindFinalizer:
2217         _ASSERTE(pvRootID == NULL);
2218         break;
2219
2220     case kEtwGCRootKindOther:
2221     default:
2222         _ASSERTE(nRootKind == kEtwGCRootKindOther);
2223         _ASSERTE(pvRootID == NULL);
2224         break;
2225     }
2226     
2227     // Convert GC root flags to ETW root flags
2228     if (dwGCFlags & GC_CALL_INTERIOR)
2229         rootFlags |= kEtwGCRootFlagsInterior;
2230     if (dwGCFlags & GC_CALL_PINNED)
2231         rootFlags |= kEtwGCRootFlagsPinning;
2232
2233     // Add root edge to appropriate buffer
2234     if (fDependentHandle)
2235     {
2236         _ASSERTE(pContext->cGCBulkRootConditionalWeakTableElementEdges < 
2237             _countof(pContext->rgGCBulkRootConditionalWeakTableElementEdges));
2238         EventStructGCBulkRootConditionalWeakTableElementEdgeValue * pRCWTEEdgeValue =
2239             &pContext->rgGCBulkRootConditionalWeakTableElementEdges[pContext->cGCBulkRootConditionalWeakTableElementEdges];
2240         pRCWTEEdgeValue->GCKeyNodeID = pRootedNode;
2241         pRCWTEEdgeValue->GCValueNodeID = pSecondaryNodeForDependentHandle;
2242         pRCWTEEdgeValue->GCRootID = pvRootID;
2243         pContext->cGCBulkRootConditionalWeakTableElementEdges++;
2244
2245         // If RCWTE edge buffer is now full, empty it into ETW
2246         if (pContext->cGCBulkRootConditionalWeakTableElementEdges == 
2247             _countof(pContext->rgGCBulkRootConditionalWeakTableElementEdges))
2248         {
2249             FireEtwGCBulkRootConditionalWeakTableElementEdge(
2250                 pContext->iCurBulkRootConditionalWeakTableElementEdge,
2251                 pContext->cGCBulkRootConditionalWeakTableElementEdges,
2252                 GetClrInstanceId(),
2253                 sizeof(pContext->rgGCBulkRootConditionalWeakTableElementEdges[0]),
2254                 &pContext->rgGCBulkRootConditionalWeakTableElementEdges[0]);
2255
2256             pContext->iCurBulkRootConditionalWeakTableElementEdge++;
2257             pContext->ClearRootConditionalWeakTableElementEdges();
2258         }
2259     }
2260     else
2261     {
2262         _ASSERTE(pContext->cGcBulkRootEdges < _countof(pContext->rgGcBulkRootEdges));
2263         EventStructGCBulkRootEdgeValue * pBulkRootEdgeValue = &pContext->rgGcBulkRootEdges[pContext->cGcBulkRootEdges];
2264         pBulkRootEdgeValue->RootedNodeAddress = pRootedNode;
2265         pBulkRootEdgeValue->GCRootKind = nRootKind;
2266         pBulkRootEdgeValue->GCRootFlag = rootFlags;
2267         pBulkRootEdgeValue->GCRootID = pvRootID;
2268         pContext->cGcBulkRootEdges++;
2269
2270         // If root edge buffer is now full, empty it into ETW
2271         if (pContext->cGcBulkRootEdges == _countof(pContext->rgGcBulkRootEdges))
2272         {
2273             FireEtwGCBulkRootEdge(
2274                 pContext->iCurBulkRootEdge,
2275                 pContext->cGcBulkRootEdges,
2276                 GetClrInstanceId(),
2277                 sizeof(pContext->rgGcBulkRootEdges[0]),
2278                 &pContext->rgGcBulkRootEdges[0]);
2279
2280             pContext->iCurBulkRootEdge++;
2281             pContext->ClearRootEdges();
2282         }
2283     }
2284 }
2285
2286 //---------------------------------------------------------------------------------------
2287 //
2288 // Called during a heap walk for each object reference encountered.  Batches up the
2289 // corresponding node, edges, and type data for the ETW events.
2290 //
2291 // Arguments:
2292 //      * profilerWalkHeapContext - The shared profapi/etw context built up during the heap walk.
2293 //      * pObjReferenceSource - Object doing the pointing
2294 //      * typeID - Type of pObjReferenceSource
2295 //      * fDependentHandle - nonzero iff this is for a dependent handle
2296 //      * cRefs - Count of objects being pointed to
2297 //      * rgObjReferenceTargets - Array of objects being pointed to
2298 //
2299
2300 // static
2301 VOID ETW::GCLog::ObjectReference(
2302     ProfilerWalkHeapContext * profilerWalkHeapContext,
2303     Object * pObjReferenceSource,
2304     ULONGLONG typeID,
2305     ULONGLONG cRefs,
2306     Object ** rgObjReferenceTargets)
2307 {
2308     CONTRACTL
2309     {
2310         NOTHROW;
2311         GC_NOTRIGGER;
2312         MODE_ANY;
2313
2314         // LogTypeAndParametersIfNecessary can take a lock
2315         CAN_TAKE_LOCK;
2316     }
2317     CONTRACTL_END;
2318
2319     EtwGcHeapDumpContext * pContext =
2320         EtwGcHeapDumpContext::GetOrCreateInGCContext(&profilerWalkHeapContext->pvEtwContext);
2321     if (pContext == NULL)
2322         return;
2323
2324     //---------------------------------------------------------------------------------------
2325     //    GCBulkNode events
2326     //---------------------------------------------------------------------------------------
2327
2328     // Add Node (pObjReferenceSource) to buffer
2329     _ASSERTE(pContext->cGcBulkNodeValues < _countof(pContext->rgGcBulkNodeValues));
2330     EventStructGCBulkNodeValue * pBulkNodeValue = &pContext->rgGcBulkNodeValues[pContext->cGcBulkNodeValues];
2331     pBulkNodeValue->Address = pObjReferenceSource;
2332     pBulkNodeValue->Size = pObjReferenceSource->GetSize();
2333     pBulkNodeValue->TypeID = typeID;
2334     pBulkNodeValue->EdgeCount = cRefs;
2335     pContext->cGcBulkNodeValues++;
2336
2337     // If Node buffer is now full, empty it into ETW
2338     if (pContext->cGcBulkNodeValues == _countof(pContext->rgGcBulkNodeValues))
2339     {
2340         FireEtwGCBulkNode(
2341             pContext->iCurBulkNodeEvent,
2342             pContext->cGcBulkNodeValues,
2343             GetClrInstanceId(),
2344             sizeof(pContext->rgGcBulkNodeValues[0]),
2345             &pContext->rgGcBulkNodeValues[0]);
2346
2347         pContext->iCurBulkNodeEvent++;
2348         pContext->ClearNodes();
2349     }
2350
2351     //---------------------------------------------------------------------------------------
2352     //    BulkType events
2353     //---------------------------------------------------------------------------------------
2354
2355     // We send type information as necessary--only for nodes, and only for nodes that we
2356     // haven't already sent type info for
2357     if (typeID != 0)
2358     {
2359         ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(
2360             &pContext->bulkTypeEventLogger,     // Batch up this type with others to minimize events
2361             typeID, 
2362             
2363             // During heap walk, GC holds the lock for us, so we can directly enter the
2364             // hash to see if the type has already been logged
2365             ETW::TypeSystemLog::kTypeLogBehaviorTakeLockAndLogIfFirstTime
2366             );
2367     }
2368
2369     //---------------------------------------------------------------------------------------
2370     //    GCBulkEdge events
2371     //---------------------------------------------------------------------------------------
2372
2373     // Add Edges (rgObjReferenceTargets) to buffer. Buffer could fill up before all edges
2374     // are added (it could even fill up multiple times during this one call if there are
2375     // a lot of edges), so empty Edge buffer into ETW as we go along, as many times as we
2376     // need.
2377
2378     for (ULONGLONG i=0; i < cRefs; i++)
2379     {
2380         _ASSERTE(pContext->cGcBulkEdgeValues < _countof(pContext->rgGcBulkEdgeValues));
2381         EventStructGCBulkEdgeValue * pBulkEdgeValue = &pContext->rgGcBulkEdgeValues[pContext->cGcBulkEdgeValues];
2382         pBulkEdgeValue->Value = rgObjReferenceTargets[i];
2383         // FUTURE: ReferencingFieldID 
2384         pBulkEdgeValue->ReferencingFieldID = 0;
2385         pContext->cGcBulkEdgeValues++;
2386
2387         // If Edge buffer is now full, empty it into ETW
2388         if (pContext->cGcBulkEdgeValues == _countof(pContext->rgGcBulkEdgeValues))
2389         {
2390             FireEtwGCBulkEdge(
2391                 pContext->iCurBulkEdgeEvent,
2392                 pContext->cGcBulkEdgeValues,
2393                 GetClrInstanceId(),
2394                 sizeof(pContext->rgGcBulkEdgeValues[0]),
2395                 &pContext->rgGcBulkEdgeValues[0]);
2396
2397             pContext->iCurBulkEdgeEvent++;
2398             pContext->ClearEdges();
2399         }
2400     }
2401 }
2402
2403 //---------------------------------------------------------------------------------------
2404 //
2405 // Called by GC at end of heap dump to give us a convenient time to flush any remaining
2406 // buffers of data to ETW
2407 //
2408 // Arguments:
2409 //      profilerWalkHeapContext - Context containing data we've batched up
2410 //
2411
2412 // static
2413 VOID ETW::GCLog::EndHeapDump(ProfilerWalkHeapContext * profilerWalkHeapContext)
2414 {
2415     LIMITED_METHOD_CONTRACT;
2416
2417     // If context isn't already set up for us, then we haven't been collecting any data
2418     // for ETW events.
2419     EtwGcHeapDumpContext * pContext = (EtwGcHeapDumpContext *) profilerWalkHeapContext->pvEtwContext;
2420     if (pContext == NULL)
2421         return;
2422
2423     // If the GC events are enabled, flush any remaining root, node, and / or edge data
2424     if (s_forcedGCInProgress &&
2425         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
2426                                      TRACE_LEVEL_INFORMATION, 
2427                                      CLR_GCHEAPDUMP_KEYWORD))
2428     {
2429         if (pContext->cGcBulkRootEdges > 0)
2430         {
2431             FireEtwGCBulkRootEdge(
2432                 pContext->iCurBulkRootEdge,
2433                 pContext->cGcBulkRootEdges,
2434                 GetClrInstanceId(),
2435                 sizeof(pContext->rgGcBulkRootEdges[0]),
2436                 &pContext->rgGcBulkRootEdges[0]);
2437         }
2438
2439         if (pContext->cGCBulkRootConditionalWeakTableElementEdges > 0)
2440         {
2441             FireEtwGCBulkRootConditionalWeakTableElementEdge(
2442                 pContext->iCurBulkRootConditionalWeakTableElementEdge,
2443                 pContext->cGCBulkRootConditionalWeakTableElementEdges,
2444                 GetClrInstanceId(),
2445                 sizeof(pContext->rgGCBulkRootConditionalWeakTableElementEdges[0]),
2446                 &pContext->rgGCBulkRootConditionalWeakTableElementEdges[0]);
2447         }
2448
2449         if (pContext->cGcBulkNodeValues > 0)
2450         {
2451             FireEtwGCBulkNode(
2452                 pContext->iCurBulkNodeEvent,
2453                 pContext->cGcBulkNodeValues,
2454                 GetClrInstanceId(),
2455                 sizeof(pContext->rgGcBulkNodeValues[0]),
2456                 &pContext->rgGcBulkNodeValues[0]);
2457         }
2458
2459         if (pContext->cGcBulkEdgeValues > 0)
2460         {
2461             FireEtwGCBulkEdge(
2462                 pContext->iCurBulkEdgeEvent,
2463                 pContext->cGcBulkEdgeValues,
2464                 GetClrInstanceId(),
2465                 sizeof(pContext->rgGcBulkEdgeValues[0]),
2466                 &pContext->rgGcBulkEdgeValues[0]);
2467         }
2468     }
2469
2470     // Ditto for type events
2471     if (ETW_TRACING_CATEGORY_ENABLED(
2472         MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
2473         TRACE_LEVEL_INFORMATION, 
2474         CLR_TYPE_KEYWORD))
2475     {
2476         pContext->bulkTypeEventLogger.FireBulkTypeEvent();
2477     }
2478
2479     // Delete any GC state built up in the context
2480     profilerWalkHeapContext->pvEtwContext = NULL;
2481     delete pContext;
2482 }
2483
2484
2485 //---------------------------------------------------------------------------------------
2486 //
2487 // Helper to send public finalize object & type events, and private finalize object
2488 // event.  If Type events are enabled, this will send the Type event for the finalized
2489 // objects.  It will not be batched with other types (except type parameters, if any),
2490 // and will not check if the Type has already been logged (may thus result in dupe
2491 // logging of the Type).
2492 //
2493 // Arguments:
2494 //      pMT - MT of object getting finalized
2495 //      pObj - object getting finalized
2496 //
2497
2498 // static
2499 VOID ETW::GCLog::SendFinalizeObjectEvent(MethodTable * pMT, Object * pObj)
2500 {
2501     CONTRACTL
2502     {
2503         NOTHROW;
2504         GC_NOTRIGGER;
2505         MODE_ANY;
2506
2507         // LogTypeAndParameters locks, and we take our own lock if typeLogBehavior says to
2508         CAN_TAKE_LOCK;
2509     }
2510     CONTRACTL_END;
2511
2512     // Send public finalize object event, if it's enabled
2513     if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, FinalizeObject))
2514     {
2515         FireEtwFinalizeObject(pMT, pObj, GetClrInstanceId());
2516         
2517         // This function checks if type events are enabled; if so, it sends event for
2518         // finalized object's type (and parameter types, if any)
2519         ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(
2520             NULL,       // Not batching this type with others
2521             (TADDR) pMT,
2522             
2523             // Don't spend the time entering the lock and checking the hash table to see
2524             // if we've already logged the type; just log it (if type events are enabled).
2525             ETW::TypeSystemLog::kTypeLogBehaviorAlwaysLog
2526             );
2527     }
2528
2529     // Send private finalize object event, if it's enabled
2530     if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, PrvFinalizeObject))
2531     {
2532         EX_TRY
2533         {
2534             DefineFullyQualifiedNameForClassWOnStack();
2535             FireEtwPrvFinalizeObject(pMT, pObj, GetClrInstanceId(), GetFullyQualifiedNameForClassNestedAwareW(pMT));
2536         }
2537         EX_CATCH
2538         {
2539         }
2540         EX_END_CATCH(RethrowCorruptingExceptions);
2541     }
2542 }
2543
2544
2545 DWORD ETW::ThreadLog::GetEtwThreadFlags(Thread * pThread)
2546 {
2547     LIMITED_METHOD_CONTRACT;
2548
2549     DWORD dwEtwThreadFlags = 0;
2550
2551     if (pThread->IsThreadPoolThread())
2552     {
2553         dwEtwThreadFlags |= kEtwThreadFlagThreadPoolWorker;
2554     }
2555     if (pThread->IsGCSpecial())
2556     {
2557         dwEtwThreadFlags |= kEtwThreadFlagGCSpecial;
2558     }
2559     if (IsGarbageCollectorFullyInitialized() &&
2560         (pThread == FinalizerThread::GetFinalizerThread()))
2561     {
2562         dwEtwThreadFlags |= kEtwThreadFlagFinalizer;
2563     }
2564
2565     return dwEtwThreadFlags;
2566 }
2567
2568 VOID ETW::ThreadLog::FireThreadCreated(Thread * pThread)
2569 {
2570     LIMITED_METHOD_CONTRACT;
2571
2572     FireEtwThreadCreated(
2573         (ULONGLONG)pThread, 
2574         (ULONGLONG)pThread->GetDomain(), 
2575         GetEtwThreadFlags(pThread),
2576         pThread->GetThreadId(),
2577         pThread->GetOSThreadId(), 
2578         GetClrInstanceId());
2579 }
2580
2581 VOID ETW::ThreadLog::FireThreadDC(Thread * pThread)
2582 {
2583     LIMITED_METHOD_CONTRACT;
2584
2585     FireEtwThreadDC(
2586         (ULONGLONG)pThread, 
2587         (ULONGLONG)pThread->GetDomain(), 
2588         GetEtwThreadFlags(pThread),
2589         pThread->GetThreadId(),
2590         pThread->GetOSThreadId(), 
2591         GetClrInstanceId());
2592 }
2593
2594
2595
2596 #ifndef FEATURE_REDHAWK
2597
2598 // TypeSystemLog implementation
2599 // 
2600 // We keep track of which TypeHandles have been logged, and stats on instances of these
2601 // TypeHandles that have been allocated, by a hash table of hash tables. The outer hash
2602 // table maps Module*'s to an inner hash table that contains all the TypeLoggingInfos for that
2603 // Module*. Arranging things this way makes it easy to deal with Module unloads, as we
2604 // can simply remove the corresponding inner hash table from the outer hash table.
2605
2606 // The following help define the "inner" hash table: a hash table of TypeLoggingInfos
2607 // from a particular Module (key = TypeHandle, value = TypeLoggingInfo.
2608
2609 class LoggedTypesFromModuleTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ETW::TypeLoggingInfo> >
2610 {
2611 public:
2612
2613     // explicitly declare local typedefs for these traits types, otherwise 
2614     // the compiler may get confused
2615     typedef NoRemoveSHashTraits< DefaultSHashTraits<ETW::TypeLoggingInfo> > PARENT;
2616     typedef PARENT::element_t element_t;
2617     typedef PARENT::count_t count_t;
2618
2619     typedef TypeHandle key_t;
2620
2621     static key_t GetKey(const element_t &e)
2622     {
2623         LIMITED_METHOD_CONTRACT;
2624         return e.th;
2625     }
2626
2627     static BOOL Equals(key_t k1, key_t k2)
2628     {
2629         LIMITED_METHOD_CONTRACT;
2630         return (k1 == k2);
2631     }
2632
2633     static count_t Hash(key_t k)
2634     {
2635         LIMITED_METHOD_CONTRACT;
2636         return (count_t) k.AsTAddr();
2637     }
2638
2639     static bool IsNull(const element_t &e)
2640     {
2641         LIMITED_METHOD_CONTRACT;
2642         return (e.th.AsTAddr() == NULL);
2643     }
2644
2645     static const element_t Null()
2646     {
2647         LIMITED_METHOD_CONTRACT;
2648         return ETW::TypeLoggingInfo(NULL);
2649     }
2650 };
2651 typedef SHash<LoggedTypesFromModuleTraits> LoggedTypesFromModuleHash;
2652
2653 // The inner hash table is housed inside this class, which acts as an entry in the outer
2654 // hash table.
2655 class ETW::LoggedTypesFromModule
2656 {
2657 public:
2658     Module * pModule;
2659     LoggedTypesFromModuleHash loggedTypesFromModuleHash;
2660
2661     // These are used by the outer hash table (mapping Module*'s to instances of
2662     // LoggedTypesFromModule).
2663     static COUNT_T Hash(Module * pModule) 
2664     {
2665         LIMITED_METHOD_CONTRACT;
2666         return (COUNT_T) (SIZE_T) pModule; 
2667     }
2668     Module * GetKey() 
2669     {
2670         LIMITED_METHOD_CONTRACT;
2671         return pModule; 
2672     }
2673
2674     LoggedTypesFromModule(Module * pModuleParam) : loggedTypesFromModuleHash()
2675     {
2676         LIMITED_METHOD_CONTRACT;
2677         pModule = pModuleParam;
2678     }
2679
2680     ~LoggedTypesFromModule()
2681     {
2682         LIMITED_METHOD_CONTRACT;
2683     }
2684 };
2685
2686 // The following define the outer hash table (mapping Module*'s to instances of
2687 // LoggedTypesFromModule).
2688
2689 class AllLoggedTypesTraits : public DefaultSHashTraits<ETW::LoggedTypesFromModule *>
2690 {
2691 public:
2692
2693     // explicitly declare local typedefs for these traits types, otherwise 
2694     // the compiler may get confused
2695     typedef DefaultSHashTraits<ETW::LoggedTypesFromModule *> PARENT;
2696     typedef PARENT::element_t element_t;
2697     typedef PARENT::count_t count_t;
2698
2699     typedef Module * key_t;
2700
2701     static key_t GetKey(const element_t &e)
2702     {
2703         LIMITED_METHOD_CONTRACT;
2704         return e->pModule;
2705     }
2706
2707     static BOOL Equals(key_t k1, key_t k2)
2708     {
2709         LIMITED_METHOD_CONTRACT;
2710         return (k1 == k2);
2711     }
2712
2713     static count_t Hash(key_t k)
2714     {
2715         LIMITED_METHOD_CONTRACT;
2716         return (count_t) (size_t) k;
2717     }
2718
2719     static bool IsNull(const element_t &e)
2720     {
2721         LIMITED_METHOD_CONTRACT;
2722         return (e == NULL);
2723     }
2724
2725     static element_t Null()
2726     {
2727         LIMITED_METHOD_CONTRACT;
2728         return NULL; 
2729     }
2730 };
2731
2732 typedef SHash<AllLoggedTypesTraits> AllLoggedTypesHash;
2733
2734 // The outer hash table (mapping Module*'s to instances of LoggedTypesFromModule) is
2735 // housed in this struct, which is dynamically allocated the first time we decide we need
2736 // it.
2737 struct AllLoggedTypes
2738 {
2739 public:
2740     // This Crst protects the entire outer & inner hash tables.  On a GC heap walk, it
2741     // is entered once for the duration of the walk, so that we can freely access the
2742     // hash tables during the walk.  On each object allocation, this Crst must be
2743     // entered individually each time.
2744     static CrstStatic s_cs;
2745
2746     // A thread local copy of the global epoch.
2747     // This value is used by each thread to ensure that the thread local data structures 
2748     // are in sync with the global state.
2749     unsigned int nEpoch;
2750     
2751     // The outer hash table (mapping Module*'s to instances of LoggedTypesFromModule)
2752     AllLoggedTypesHash allLoggedTypesHash;
2753 };
2754
2755
2756 CrstStatic AllLoggedTypes::s_cs;
2757 AllLoggedTypes * ETW::TypeSystemLog::s_pAllLoggedTypes = NULL;
2758 unsigned int ETW::TypeSystemLog::s_nEpoch = 0;
2759 BOOL ETW::TypeSystemLog::s_fHeapAllocEventEnabledOnStartup = FALSE;
2760 BOOL ETW::TypeSystemLog::s_fHeapAllocHighEventEnabledNow = FALSE;
2761 BOOL ETW::TypeSystemLog::s_fHeapAllocLowEventEnabledNow = FALSE;
2762 int ETW::TypeSystemLog::s_nCustomMsBetweenEvents = 0;
2763
2764
2765 //---------------------------------------------------------------------------------------
2766 //
2767 // Initializes TypeSystemLog (specifically its crst).  Called just before ETW providers
2768 // are registered with the OS
2769 //
2770 // Return Value:
2771 //     HRESULT indicating success or failure
2772 //
2773
2774 // static
2775 HRESULT ETW::TypeSystemLog::PreRegistrationInit()
2776 {
2777     LIMITED_METHOD_CONTRACT;
2778
2779     if (!AllLoggedTypes::s_cs.InitNoThrow(
2780         CrstEtwTypeLogHash, 
2781         CRST_UNSAFE_ANYMODE))       // This lock is taken during a GC while walking the heap
2782     {
2783         return E_FAIL;
2784     }
2785
2786     return S_OK;
2787 }
2788
2789 //---------------------------------------------------------------------------------------
2790 //
2791 // Initializes TypeSystemLog (specifically its crst).  Called just after ETW providers
2792 // are registered with the OS
2793 //
2794 // Return Value:
2795 //     HRESULT indicating success or failure
2796 //
2797
2798 // static
2799 void ETW::TypeSystemLog::PostRegistrationInit()
2800 {
2801     LIMITED_METHOD_CONTRACT;
2802
2803     // Initialize our "current state" BOOLs that remember if low or high allocation
2804     // sampling is turned on
2805     s_fHeapAllocLowEventEnabledNow = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_GCHEAPALLOCLOW_KEYWORD);
2806     s_fHeapAllocHighEventEnabledNow = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_GCHEAPALLOCHIGH_KEYWORD);
2807
2808     // Snapshot the current state of the object allocated keyword (on startup), and rely
2809     // on this snapshot for the rest of the process run. Since these events require the
2810     // slow alloc JIT helper to be enabled, and that can only be done on startup, we
2811     // remember in this BOOL that we did so, so that we can prevent the object allocated
2812     // event from being fired if the fast allocation helper were enabled but had to
2813     // degrade down to the slow helper (e.g., thread ran over its allocation limit). This
2814     // keeps things consistent.
2815     s_fHeapAllocEventEnabledOnStartup = (s_fHeapAllocLowEventEnabledNow || s_fHeapAllocHighEventEnabledNow);
2816
2817     if (s_fHeapAllocEventEnabledOnStartup)
2818     {
2819         // Determine if a COMPLUS env var is overriding the frequency for the sampled
2820         // object allocated events
2821         
2822         // Config value intentionally typed as string, b/c DWORD intepretation is hard-coded
2823         // to hex, which is not what the user would expect.  This way I can force the
2824         // conversion to use decimal.
2825         NewArrayHolder<WCHAR> wszCustomObjectAllocationEventsPerTypePerSec(NULL);
2826         if (FAILED(CLRConfig::GetConfigValue(
2827             CLRConfig::UNSUPPORTED_ETW_ObjectAllocationEventsPerTypePerSec, 
2828             &wszCustomObjectAllocationEventsPerTypePerSec)) ||
2829             (wszCustomObjectAllocationEventsPerTypePerSec == NULL))
2830         {
2831             return;
2832         }
2833         LPWSTR endPtr;
2834         DWORD dwCustomObjectAllocationEventsPerTypePerSec = wcstoul(
2835             wszCustomObjectAllocationEventsPerTypePerSec,
2836             &endPtr,
2837             10          // Base 10 conversion
2838             );
2839
2840         if (dwCustomObjectAllocationEventsPerTypePerSec == ULONG_MAX)
2841             dwCustomObjectAllocationEventsPerTypePerSec = 0;
2842         if (dwCustomObjectAllocationEventsPerTypePerSec != 0)
2843         {
2844             // MsBetweenEvents = (1000 ms/sec) / (custom desired events/sec)
2845             s_nCustomMsBetweenEvents = 1000 / dwCustomObjectAllocationEventsPerTypePerSec;
2846         }
2847     }
2848 }
2849
2850
2851 //---------------------------------------------------------------------------------------
2852 //
2853 // Update object allocation sampling frequency and / or Type hash table contents based
2854 // on what keywords were changed.
2855 //
2856
2857 // static
2858 void ETW::TypeSystemLog::OnKeywordsChanged()
2859 {
2860     LIMITED_METHOD_CONTRACT;
2861
2862     // If the desired frequencey for the GCSampledObjectAllocation events has changed,
2863     // update our state.
2864     s_fHeapAllocLowEventEnabledNow = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_GCHEAPALLOCLOW_KEYWORD);
2865     s_fHeapAllocHighEventEnabledNow = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_GCHEAPALLOCHIGH_KEYWORD);
2866
2867     // FUTURE: Would be nice here to log an error event if (s_fHeapAllocLowEventEnabledNow ||
2868     // s_fHeapAllocHighEventEnabledNow), but !s_fHeapAllocEventEnabledOnStartup
2869
2870     // If the type events should be turned off, eliminate the hash tables that tracked
2871     // which types were logged. (If type events are turned back on later, we'll re-log
2872     // them all as we encounter them.) Note that all we can really test for is that the
2873     // Types keyword on the runtime provider is off. Not necessarily that it was on and
2874     // was just turned off with this request. But either way, TypeSystemLog can handle it
2875     // because it is extremely smart.
2876     if (!ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_TYPE_KEYWORD))
2877         OnTypesKeywordTurnedOff();
2878 }
2879
2880
2881 //---------------------------------------------------------------------------------------
2882 //
2883 // Based on keywords alone, determine the what the default sampling rate should be for
2884 // object allocation events.  (This function does not consider any COMPLUS overrides for
2885 // the sampling rate.)
2886 //
2887
2888 // static
2889 int ETW::TypeSystemLog::GetDefaultMsBetweenEvents()
2890 {
2891     LIMITED_METHOD_CONTRACT;
2892
2893     // We should only get here if the allocation event is enabled. In spirit, this assert
2894     // is correct, but a race could cause the assert to fire (if someone toggled the
2895     // event off after we decided that the event was on and we started down the path of
2896     // calculating statistics to fire the event). In such a case we'll end up returning
2897     // k_nDefaultMsBetweenEventsLow below, but next time we won't get here as we'll know
2898     // early enough not to fire the event.
2899     //_ASSERTE(IsHeapAllocEventEnabled());
2900
2901     // MsBetweenEvents = (1000 ms/sec) / (desired events/sec)
2902     const int k_nDefaultMsBetweenEventsHigh = 1000 / 100;   // 100 events per type per sec
2903     const int k_nDefaultMsBetweenEventsLow = 1000 / 5;      // 5 events per type per sec
2904
2905     // If both are set, High takes precedence
2906     if (s_fHeapAllocHighEventEnabledNow)
2907     {
2908         return k_nDefaultMsBetweenEventsHigh;
2909     }
2910     return k_nDefaultMsBetweenEventsLow;
2911 }
2912
2913 //---------------------------------------------------------------------------------------
2914 //
2915 // Use this to decide whether to fire the object allocation event
2916 //
2917 // Return Value:
2918 //      nonzero iff we should fire the event.
2919 //
2920
2921 // static
2922 BOOL ETW::TypeSystemLog::IsHeapAllocEventEnabled()
2923 {
2924     LIMITED_METHOD_CONTRACT;
2925
2926     return 
2927         // Only fire the event if it was enabled at startup (and thus the slow-JIT new
2928         // helper is used in all cases)
2929         s_fHeapAllocEventEnabledOnStartup &&
2930
2931         // AND a keyword is still enabled.  (Thus people can turn off the event
2932         // whenever they want; but they cannot turn it on unless it was also on at startup.)
2933         (s_fHeapAllocHighEventEnabledNow || s_fHeapAllocLowEventEnabledNow);
2934 }
2935
2936 //---------------------------------------------------------------------------------------
2937 //
2938 // Helper that adds (or updates) the TypeLoggingInfo inside the inner hash table passed
2939 // in.
2940 //
2941 // Arguments:
2942 //      * pLoggedTypesFromModule - Inner hash table to update
2943 //      * pTypeLoggingInfo - TypeLoggingInfo to store
2944 //
2945 // Return Value:
2946 //      nonzero iff the add/replace was successful.
2947 //
2948
2949 // static
2950 BOOL ETW::TypeSystemLog::AddOrReplaceTypeLoggingInfo(ETW::LoggedTypesFromModule * pLoggedTypesFromModule, const ETW::TypeLoggingInfo * pTypeLoggingInfo)
2951 {
2952     LIMITED_METHOD_CONTRACT;
2953
2954     _ASSERTE(pLoggedTypesFromModule != NULL);
2955
2956     BOOL fSucceeded = FALSE;
2957     EX_TRY
2958     {
2959         pLoggedTypesFromModule->loggedTypesFromModuleHash.AddOrReplace(*pTypeLoggingInfo);
2960         fSucceeded = TRUE;
2961     }
2962     EX_CATCH
2963     {
2964         fSucceeded = FALSE;
2965     }
2966     EX_END_CATCH(RethrowCorruptingExceptions);
2967
2968     return fSucceeded;
2969 }
2970
2971 //---------------------------------------------------------------------------------------
2972 //
2973 // Records stats about the object's allocation, and determines based on those stats whether
2974 // to fires the high / low frequency GCSampledObjectAllocation ETW event
2975 //
2976 // Arguments:
2977 //      * pObject - Allocated object to log
2978 //      * th - TypeHandle for the object
2979 //
2980
2981 // static
2982 void ETW::TypeSystemLog::SendObjectAllocatedEvent(Object * pObject)
2983 {
2984     CONTRACTL
2985     {
2986         NOTHROW;
2987         GC_NOTRIGGER;
2988         MODE_COOPERATIVE;
2989     }
2990     CONTRACTL_END;
2991
2992     // No-op if the appropriate keywords were not enabled on startup (or we're not yet
2993     // started up)
2994     if (!s_fHeapAllocEventEnabledOnStartup || !g_fEEStarted)
2995         return;
2996
2997     TypeHandle th = pObject->GetTypeHandle();
2998
2999     SIZE_T size = pObject->GetSize();
3000     if (size < MIN_OBJECT_SIZE)
3001     {
3002         size = PtrAlign(size);
3003     }
3004
3005     SIZE_T nTotalSizeForTypeSample = size;
3006     DWORD dwTickNow = GetTickCount();
3007     DWORD dwObjectCountForTypeSample = 0;
3008
3009     // Get stats for type
3010     TypeLoggingInfo typeLoggingInfo(NULL);
3011     LoggedTypesFromModule * pLoggedTypesFromModule = NULL;
3012     BOOL fCreatedNew = FALSE;
3013     typeLoggingInfo = LookupOrCreateTypeLoggingInfo(th, &fCreatedNew, &pLoggedTypesFromModule);
3014     if (typeLoggingInfo.th.IsNull())
3015         return;
3016
3017     // Update stats with current allocation
3018     typeLoggingInfo.dwAllocsSkippedForSample++;
3019     typeLoggingInfo.cbIgnoredSizeForSample += size;
3020
3021     // If both the high and low verbosity keywords are enabled, log all allocations.
3022     if (!(s_fHeapAllocHighEventEnabledNow && s_fHeapAllocLowEventEnabledNow))
3023     {
3024         // Get the number of threads so that we can scale the per-thread sampling data.
3025         // NOTE: We don't do this while holding the thread store lock, so this may not be perfect,
3026         // but it will be close enough.
3027         LONG numThreads = ThreadStore::s_pThreadStore->ThreadCountInEE();
3028
3029         // This is our filter. If we should ignore this alloc, then record our updated
3030         // our stats, and bail without sending the event. Note that we always log objects
3031         // over 10K in size.
3032         if (size < 10000 && typeLoggingInfo.dwAllocsSkippedForSample < (typeLoggingInfo.dwAllocsToSkipPerSample * numThreads))
3033         {
3034             // Update hash table's copy of type logging info with these values.  It is not optimal that
3035             // we're doing another hash table lookup here.  Could instead have used LookupPtr()
3036             // if it gave us back a non-const pointer, and then we could have updated in-place
3037             AddOrReplaceTypeLoggingInfo(pLoggedTypesFromModule, &typeLoggingInfo);
3038             if (fCreatedNew)
3039             {
3040                 // Although we're skipping logging the allocation, we still need to log
3041                 // the type (so it's available for resolving future allocation events to
3042                 // their types).
3043                 // 
3044                 // (See other call to LogTypeAndParametersIfNecessary further down for
3045                 // more comments.)
3046                 LogTypeAndParametersIfNecessary(
3047                     NULL,
3048                     th.AsTAddr(),
3049                     kTypeLogBehaviorAlwaysLogTopLevelType);
3050             }
3051             return;
3052         }
3053
3054         // Based on observed allocation stats, adjust our sampling rate for this type
3055
3056         typeLoggingInfo.dwAllocCountInCurrentBucket += typeLoggingInfo.dwAllocsSkippedForSample;
3057         int delta = (dwTickNow - typeLoggingInfo.dwTickOfCurrentTimeBucket) & 0x7FFFFFFF;       // make wrap around work.  
3058
3059         int nMinAllocPerMSec = typeLoggingInfo.dwAllocCountInCurrentBucket / 16 / numThreads;           // This is an underestimation of the true rate.  
3060         if (delta >= 16 || (nMinAllocPerMSec > 2 && nMinAllocPerMSec > typeLoggingInfo.flAllocPerMSec * 1.5F))
3061         {
3062             float flNewAllocPerMSec  = 0;
3063             if (delta >= 16)
3064             {
3065                 // This is the normal case, our allocation rate is under control with the current throttling.   
3066                 flNewAllocPerMSec  = ((float) typeLoggingInfo.dwAllocCountInCurrentBucket) / delta;
3067                 // Do a exponential decay window that is 5 * max(16, AllocationInterval)  
3068                 typeLoggingInfo.flAllocPerMSec = 0.8F *  typeLoggingInfo.flAllocPerMSec + 0.2F * flNewAllocPerMSec; 
3069                 typeLoggingInfo.dwTickOfCurrentTimeBucket = dwTickNow;
3070                 typeLoggingInfo.dwAllocCountInCurrentBucket = 0;
3071             }
3072             else 
3073             {
3074                 flNewAllocPerMSec = (float) nMinAllocPerMSec;
3075                 // This means the second clause above is true, which means our sampling rate is too low
3076                 // so we need to throttle quickly. 
3077                 typeLoggingInfo.flAllocPerMSec = flNewAllocPerMSec;
3078             }
3079
3080
3081             // Obey the desired sampling rate, but don't ignore > 1000 allocations per second
3082             // per type
3083             int nDesiredMsBetweenEvents = (s_nCustomMsBetweenEvents == 0) ? GetDefaultMsBetweenEvents() : s_nCustomMsBetweenEvents;
3084             typeLoggingInfo.dwAllocsToSkipPerSample = min((int) (typeLoggingInfo.flAllocPerMSec * nDesiredMsBetweenEvents), 1000);
3085             if (typeLoggingInfo.dwAllocsToSkipPerSample == 1)
3086                 typeLoggingInfo.dwAllocsToSkipPerSample = 0;
3087         }
3088     }
3089
3090     // We're logging this sample, so save the values we need into locals, and reset
3091     // our counts for the next sample.
3092     nTotalSizeForTypeSample = typeLoggingInfo.cbIgnoredSizeForSample;
3093     dwObjectCountForTypeSample = typeLoggingInfo.dwAllocsSkippedForSample;
3094     typeLoggingInfo.cbIgnoredSizeForSample = 0;
3095     typeLoggingInfo.dwAllocsSkippedForSample = 0;
3096
3097     // Save updated stats into hash table
3098     if (!AddOrReplaceTypeLoggingInfo(pLoggedTypesFromModule, &typeLoggingInfo))
3099     {
3100         return;
3101     }
3102
3103     // While we're still holding the crst, optionally log any relevant Types now (we may need
3104     // to reconsult the hash in here if there are any type parameters, though we can
3105     // optimize and NOT consult the hash for th itself).
3106     if (fCreatedNew)
3107     {
3108         // We were the ones to add the Type to the hash.  So it wasn't there before,
3109         // which means it hasn't been logged yet.
3110         LogTypeAndParametersIfNecessary(
3111
3112             // No BulkTypeEventLogger, as we're not batching during a GC heap walk
3113             NULL,                           
3114                 
3115             th.AsTAddr(), 
3116
3117             // We've determined the type is not yet logged, so no need to check
3118             kTypeLogBehaviorAlwaysLogTopLevelType);
3119     }
3120
3121     // Now log the allocation
3122     if (s_fHeapAllocHighEventEnabledNow)
3123     {
3124         FireEtwGCSampledObjectAllocationHigh(pObject, (LPVOID) th.AsTAddr(), dwObjectCountForTypeSample, nTotalSizeForTypeSample, GetClrInstanceId());
3125     }
3126     else
3127     {
3128         FireEtwGCSampledObjectAllocationLow(pObject, (LPVOID) th.AsTAddr(), dwObjectCountForTypeSample, nTotalSizeForTypeSample, GetClrInstanceId());
3129     }
3130 }
3131
3132 //---------------------------------------------------------------------------------------
3133 //
3134 // Accessor for global hash table crst
3135 //
3136 // Return Value:
3137 //      global hash table crst
3138 //
3139
3140 // static
3141 CrstBase * ETW::TypeSystemLog::GetHashCrst()
3142 {
3143     LIMITED_METHOD_CONTRACT;
3144     return &AllLoggedTypes::s_cs;
3145 }
3146
3147 //---------------------------------------------------------------------------------------
3148 //
3149 // Outermost level of ETW-type-logging.  Clients outside eventtrace.cpp call this to log
3150 // a TypeHandle and (recursively) its type parameters when present.  This guy then calls
3151 // into the appropriate BulkTypeEventLogger to do the batching and logging
3152 //
3153 // Arguments:
3154 //      * pBulkTypeEventLogger - If our caller is keeping track of batched types, it
3155 //          passes this to us so we can use it to batch the current type (GC heap walk
3156 //          does this).  If this is NULL, no batching is going on (e.g., we're called on
3157 //          object allocation, not a GC heal walk), in which case we create our own
3158 //          temporary BulkTypeEventLogger.
3159 //      * thAsAddr - TypeHandle to batch
3160 //      * typeLogBehavior - Optimization to tell us we don't need to enter the
3161 //          TypeSystemLog's crst, as the TypeSystemLog's hash table is already protected
3162 //          by a prior acquisition of the crst by our caller.  (Or that we don't even
3163 //          need to check the hash in the first place.)
3164 //
3165
3166 // static
3167 VOID ETW::TypeSystemLog::LogTypeAndParametersIfNecessary(BulkTypeEventLogger * pLogger, ULONGLONG thAsAddr, TypeLogBehavior typeLogBehavior)
3168 {
3169     CONTRACTL
3170     {
3171         NOTHROW;
3172         GC_NOTRIGGER;
3173         MODE_ANY;
3174
3175         // LogTypeAndParameters locks, and we take our own lock if typeLogBehavior says to
3176         CAN_TAKE_LOCK;
3177     }
3178     CONTRACTL_END;
3179
3180     if (!ETW_TRACING_CATEGORY_ENABLED(
3181         MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3182         TRACE_LEVEL_INFORMATION, 
3183         CLR_TYPE_KEYWORD))
3184     {
3185         return;
3186     }
3187
3188     TypeHandle th = TypeHandle::FromTAddr((TADDR) thAsAddr);
3189     if (!th.IsRestored())
3190     {
3191         return;
3192     }
3193
3194     // Check to see if we've already logged this type.  If so, bail immediately. 
3195     // Otherwise, mark that it's getting logged (by adding it to the hash), and fall
3196     // through to the logging code below.  If caller doesn't care, then don't even
3197     // check; just log the type
3198     BOOL fShouldLogType = ((typeLogBehavior == kTypeLogBehaviorAlwaysLog) || 
3199                            (typeLogBehavior == kTypeLogBehaviorAlwaysLogTopLevelType)) ?
3200                            TRUE : 
3201                                ShouldLogType(th);
3202     if (!fShouldLogType)
3203         return;
3204
3205     if (pLogger == NULL)
3206     {
3207         // We're not batching this type against previous types (e.g., we're being called
3208         // on object allocate instead of a GC heap walk).  So create a temporary logger
3209         // on the stack.  If there are generic parameters that need to be logged, then
3210         // at least they'll get batched together with the type
3211         BulkTypeEventLogger logger;
3212         logger.LogTypeAndParameters(thAsAddr, typeLogBehavior);
3213
3214         // Since this logger isn't being used to batch anything else, flush what we have
3215         logger.FireBulkTypeEvent();
3216     }
3217     else
3218     {
3219         // We are batching this type with others (e.g., we're being called at the end of
3220         // a GC on a heap walk).  So use the logger our caller set up for us.
3221         pLogger->LogTypeAndParameters(thAsAddr, typeLogBehavior);
3222     }
3223 }
3224
3225
3226 //---------------------------------------------------------------------------------------
3227 //
3228 // Ask hash table if we've already logged the type, without first acquiring the lock
3229 // (our caller already did this).  As a side-effect, a TypeLoggingInfo will be created
3230 // for this type (so future calls to this function will return FALSE to avoid dupe type
3231 // logging).
3232 //
3233 // Arguments:
3234 //      pth - TypeHandle to query
3235 //
3236 // Return Value:
3237 //      nonzero iff type should be logged (i.e., not previously logged)
3238 //
3239
3240 // static
3241 BOOL ETW::TypeSystemLog::ShouldLogType(TypeHandle th)
3242 {
3243     CONTRACTL
3244     {
3245         NOTHROW;
3246         GC_NOTRIGGER;
3247         MODE_ANY;
3248         CAN_TAKE_LOCK;
3249     }
3250     CONTRACTL_END;
3251
3252
3253     // Check to see if TypeLoggingInfo exists yet for th.  If not, creates one and
3254     // adds it to the hash.
3255     BOOL fCreatedNew = FALSE;
3256
3257     // When we have a thread context, default to calling the API that requires one which
3258     // reduces the cost of locking.
3259     if (GetThread() != NULL)
3260     {
3261         LookupOrCreateTypeLoggingInfo(th, &fCreatedNew);
3262     }
3263     else
3264     {
3265         AddTypeToGlobalCacheIfNotExists(th, &fCreatedNew);
3266     }
3267     
3268     // Return whether we had to create the TypeLoggingInfo (indicating it was not yet in
3269     // the hash, and thus that we hadn't yet logged the type).
3270     return fCreatedNew;
3271 }
3272
3273
3274 //---------------------------------------------------------------------------------------
3275 //
3276 // Helper that returns (creating if necessary) the TypeLoggingInfo in the hash table
3277 // corresponding with the specified TypeHandle
3278 //
3279 // Arguments:
3280 //      * th - Key to lookup the TypeLoggingInfo
3281 //      * pfCreatedNew - [out] Points to nonzero iff a new TypeLoggingInfo was created
3282 //          (i.e., none existed yet in the hash for th).
3283 //      * ppLoggedTypesFromModule - [out] Points to the inner hash that was used to do
3284 //          the lookup.  (An otpimization so the caller doesn't have to find this again,
3285 //          if it needs to do further operations on it.)
3286 //
3287 // Return Value:
3288 //      TypeLoggingInfo found or created.
3289 //
3290 //
3291
3292 // static
3293 ETW::TypeLoggingInfo ETW::TypeSystemLog::LookupOrCreateTypeLoggingInfo(TypeHandle th, BOOL * pfCreatedNew, LoggedTypesFromModule ** ppLoggedTypesFromModule /* = NULL */)
3294 {
3295     //LIMITED_METHOD_CONTRACT;
3296     CONTRACTL
3297     {
3298         NOTHROW;
3299         GC_NOTRIGGER;
3300         MODE_ANY;
3301     }
3302     CONTRACTL_END;
3303
3304     _ASSERTE(pfCreatedNew != NULL);
3305
3306     if (ppLoggedTypesFromModule != NULL)
3307     {
3308         *ppLoggedTypesFromModule = NULL;
3309     }
3310
3311     BOOL fSucceeded = FALSE;
3312
3313     Thread *pThread = GetThread();
3314
3315     // Compare the thread local epoch value against the global epoch.
3316     // If the epoch has changed, dump the thread local state and start over.
3317     AllLoggedTypes * pThreadAllLoggedTypes = pThread->GetAllocationSamplingTable();
3318     if((pThreadAllLoggedTypes != NULL) && (pThreadAllLoggedTypes->nEpoch != s_nEpoch))
3319     {
3320         // Set the type hash pointer on the thread to NULL.
3321         pThread->SetAllocationSamplingTable(NULL);
3322
3323         // DeleteTypeHashNoLock will set pThreadAllLoggedTypes to NULL
3324         DeleteTypeHashNoLock(&pThreadAllLoggedTypes);
3325     }
3326
3327     // Create the thread local state if it doesn't exist.
3328     if (pThreadAllLoggedTypes == NULL)
3329     {
3330         pThreadAllLoggedTypes = new (nothrow) AllLoggedTypes;
3331         if (pThreadAllLoggedTypes == NULL)
3332         {
3333             // out of memory.  Bail on ETW stuff
3334             *pfCreatedNew = FALSE;
3335             return TypeLoggingInfo(NULL);
3336         }
3337
3338         // Set the epoch so we know we can track when changes to global state occur.
3339         pThreadAllLoggedTypes->nEpoch = s_nEpoch;
3340
3341         // Save the thread local state to the thread.
3342         pThread->SetAllocationSamplingTable(pThreadAllLoggedTypes);
3343     }
3344
3345     BOOL addTypeToGlobalList = FALSE;
3346
3347     // Step 1: go from LoaderModule to hash of types.
3348     
3349     Module * pLoaderModule = th.GetLoaderModule();
3350     _ASSERTE(pLoaderModule != NULL);
3351     LoggedTypesFromModule * pLoggedTypesFromModule = pThreadAllLoggedTypes->allLoggedTypesHash.Lookup(pLoaderModule);
3352     if (pLoggedTypesFromModule == NULL)
3353     {
3354         addTypeToGlobalList = TRUE;
3355         pLoggedTypesFromModule = new (nothrow) LoggedTypesFromModule(pLoaderModule);
3356         if (pLoggedTypesFromModule == NULL)
3357         {
3358             // out of memory.  Bail on ETW stuff
3359             *pfCreatedNew = FALSE;
3360             return TypeLoggingInfo(NULL);
3361         }
3362
3363         fSucceeded = FALSE;
3364         EX_TRY
3365         {
3366             pThreadAllLoggedTypes->allLoggedTypesHash.Add(pLoggedTypesFromModule);
3367             fSucceeded = TRUE;
3368         }
3369         EX_CATCH
3370         {
3371             fSucceeded = FALSE;
3372         }
3373         EX_END_CATCH(RethrowCorruptingExceptions);
3374         if (!fSucceeded)
3375         {
3376             *pfCreatedNew = FALSE;
3377             return TypeLoggingInfo(NULL);
3378         }
3379     }
3380
3381     if (ppLoggedTypesFromModule != NULL)
3382     {
3383         *ppLoggedTypesFromModule = pLoggedTypesFromModule;
3384     }
3385
3386     // Step 2: From hash of types, see if our TypeHandle is there already
3387     TypeLoggingInfo typeLoggingInfoPreexisting = pLoggedTypesFromModule->loggedTypesFromModuleHash.Lookup(th);
3388     if (!typeLoggingInfoPreexisting.th.IsNull())
3389     {
3390         // Type is already hashed, so it's already logged, so we don't need to
3391         // log it again.
3392         *pfCreatedNew = FALSE;
3393         return typeLoggingInfoPreexisting;
3394     }
3395
3396     // We haven't logged this type, so we need to continue with this function to
3397     // log it below. Add it to the hash table first so any recursive calls will
3398     // see that this type is already being taken care of
3399     addTypeToGlobalList = TRUE;
3400     fSucceeded = FALSE;
3401     TypeLoggingInfo typeLoggingInfoNew(th);
3402     EX_TRY
3403     {
3404         pLoggedTypesFromModule->loggedTypesFromModuleHash.Add(typeLoggingInfoNew);
3405         fSucceeded = TRUE;
3406     }
3407     EX_CATCH
3408     {
3409         fSucceeded = FALSE;
3410     }
3411     EX_END_CATCH(RethrowCorruptingExceptions);
3412     if (!fSucceeded)
3413     {
3414         *pfCreatedNew = FALSE;
3415         return TypeLoggingInfo(NULL);
3416     }
3417
3418     // This is the first time that we've seen this type on this thread, so we should attempt to
3419     // add it to the global list.
3420     if(!AddTypeToGlobalCacheIfNotExists(th, pfCreatedNew))
3421     {
3422         // out of memory or ETW has been disabled. Bail on ETW stuff
3423         *pfCreatedNew = FALSE;
3424         return TypeLoggingInfo(NULL);
3425     }
3426
3427     return typeLoggingInfoNew;
3428 }
3429
3430 //---------------------------------------------------------------------------------------
3431 //
3432 // Helper that creates a Type entry in the global type logging cache if one doesn't
3433 // already exist.
3434 //
3435 // Arguments:
3436 //      * th - Key to lookup or create
3437 //
3438 // Return Value:
3439 //      TRUE if the type needed to be added to the cache.
3440 //
3441 //
3442
3443 // static
3444 BOOL ETW::TypeSystemLog::AddTypeToGlobalCacheIfNotExists(TypeHandle th, BOOL * pfCreatedNew)
3445 {
3446     CONTRACTL
3447     {
3448         NOTHROW;
3449         GC_NOTRIGGER;
3450         MODE_ANY;
3451     }
3452     CONTRACTL_END;
3453
3454     BOOL fSucceeded = FALSE;
3455
3456     {
3457         CrstHolder _crst(GetHashCrst());
3458
3459         // Check if ETW is enabled, and if not, bail here.
3460         // We do this inside of the lock to ensure that we don't immediately
3461         // re-allocate the global type hash after it has been cleaned up.
3462         if (!ETW_TRACING_CATEGORY_ENABLED(
3463            MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3464             TRACE_LEVEL_INFORMATION, 
3465             CLR_TYPE_KEYWORD))
3466         {
3467             *pfCreatedNew = FALSE;
3468             return fSucceeded;
3469         }
3470
3471         if (s_pAllLoggedTypes == NULL)
3472         {
3473             s_pAllLoggedTypes = new (nothrow) AllLoggedTypes;
3474             if (s_pAllLoggedTypes == NULL)
3475             {
3476                 // out of memory.  Bail on ETW stuff
3477                 *pfCreatedNew = FALSE;
3478                 return fSucceeded;
3479             }
3480         }
3481
3482         // Step 1: go from LoaderModule to hash of types.
3483     
3484         Module * pLoaderModule = th.GetLoaderModule();
3485         _ASSERTE(pLoaderModule != NULL);
3486         LoggedTypesFromModule * pLoggedTypesFromModule = s_pAllLoggedTypes->allLoggedTypesHash.Lookup(pLoaderModule);
3487         if (pLoggedTypesFromModule == NULL)
3488         {
3489             pLoggedTypesFromModule = new (nothrow) LoggedTypesFromModule(pLoaderModule);
3490             if (pLoggedTypesFromModule == NULL)
3491             {
3492                 // out of memory.  Bail on ETW stuff
3493                 *pfCreatedNew = FALSE;
3494                 return fSucceeded;
3495             }
3496
3497             fSucceeded = FALSE;
3498             EX_TRY
3499             {
3500                 s_pAllLoggedTypes->allLoggedTypesHash.Add(pLoggedTypesFromModule);
3501                 fSucceeded = TRUE;
3502             }
3503             EX_CATCH
3504             {
3505                 fSucceeded = FALSE;
3506             }
3507             EX_END_CATCH(RethrowCorruptingExceptions);
3508             if (!fSucceeded)
3509             {
3510                 *pfCreatedNew = FALSE;
3511                 return fSucceeded;
3512             }
3513         }
3514
3515         // Step 2: From hash of types, see if our TypeHandle is there already
3516         TypeLoggingInfo typeLoggingInfoPreexisting = pLoggedTypesFromModule->loggedTypesFromModuleHash.Lookup(th);
3517         if (!typeLoggingInfoPreexisting.th.IsNull())
3518         {
3519             // Type is already hashed, so it's already logged, so we don't need to
3520             // log it again.
3521             *pfCreatedNew = FALSE;
3522             return fSucceeded;
3523         }
3524
3525         // We haven't logged this type, so we need to continue with this function to
3526         // log it below. Add it to the hash table first so any recursive calls will
3527         // see that this type is already being taken care of
3528         fSucceeded = FALSE;
3529         TypeLoggingInfo typeLoggingInfoNew(th);
3530         EX_TRY
3531         {
3532             pLoggedTypesFromModule->loggedTypesFromModuleHash.Add(typeLoggingInfoNew);
3533             fSucceeded = TRUE;
3534         }
3535         EX_CATCH
3536         {
3537             fSucceeded = FALSE;
3538         }
3539         EX_END_CATCH(RethrowCorruptingExceptions);
3540         if (!fSucceeded)
3541         {
3542             *pfCreatedNew = FALSE;
3543             return fSucceeded;
3544         }
3545     } // RELEASE: CrstHolder _crst(GetHashCrst());
3546
3547     *pfCreatedNew = TRUE;
3548     return fSucceeded;
3549
3550 }
3551
3552 //---------------------------------------------------------------------------------------
3553 //
3554 // Called when we determine if a module was unloaded, so we can clear out that module's
3555 // set of types from our hash table
3556 //
3557 // Arguments:
3558 //      pModule - Module getting unloaded
3559 //
3560
3561 // static
3562 VOID ETW::TypeSystemLog::OnModuleUnload(Module * pModule)
3563 {
3564     CONTRACTL
3565     {
3566         NOTHROW;
3567         GC_NOTRIGGER;
3568         MODE_ANY;
3569         CAN_TAKE_LOCK;
3570     }
3571     CONTRACTL_END;
3572
3573     // We don't need to do anything if allocation sampling is disabled.
3574     if (!ETW_TRACING_CATEGORY_ENABLED(
3575         MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3576         TRACE_LEVEL_INFORMATION, 
3577         CLR_TYPE_KEYWORD))
3578     {
3579         return;
3580     }
3581
3582     LoggedTypesFromModule * pLoggedTypesFromModule = NULL;
3583
3584     {
3585         CrstHolder _crst(GetHashCrst());
3586
3587         // We don't need to do anything if the global type hash doesn't contain any data.
3588         if (s_pAllLoggedTypes == NULL)
3589             return;
3590
3591         // Is there a TypesHash for this module?
3592         pLoggedTypesFromModule = s_pAllLoggedTypes->allLoggedTypesHash.Lookup(pModule);
3593         if (pLoggedTypesFromModule == NULL)
3594             return;
3595
3596         // Remove TypesHash from master hash mapping modules to their TypesHash
3597         s_pAllLoggedTypes->allLoggedTypesHash.Remove(pModule);
3598
3599         // Increment the epoch to signal the change to all threads.
3600         s_nEpoch++;
3601     }
3602
3603     // Destruct this TypesHash we just removed
3604     delete pLoggedTypesFromModule;
3605     pLoggedTypesFromModule = NULL;
3606
3607 }
3608
3609 //---------------------------------------------------------------------------------------
3610 //
3611 // Same semantics as DeleteTypeHash but assumes that the appropriate lock
3612 // has already been acquired.
3613 //
3614
3615 // static
3616 VOID ETW::TypeSystemLog::DeleteTypeHashNoLock(AllLoggedTypes **ppAllLoggedTypes)
3617 {
3618     LIMITED_METHOD_CONTRACT;
3619
3620     if(ppAllLoggedTypes == NULL)
3621     {
3622         return;
3623     }
3624
3625     AllLoggedTypes *pAllLoggedTypes = *ppAllLoggedTypes;
3626
3627     if(pAllLoggedTypes == NULL)
3628     {
3629         return;
3630     }
3631
3632     // Destruct each of the per-module TypesHashes
3633     AllLoggedTypesHash * pLoggedTypesHash = &pAllLoggedTypes->allLoggedTypesHash;
3634     for (AllLoggedTypesHash::Iterator iter = pLoggedTypesHash->Begin();
3635         iter != pLoggedTypesHash->End();
3636         ++iter)
3637     {
3638         LoggedTypesFromModule * pLoggedTypesFromModule = *iter;
3639         delete pLoggedTypesFromModule;
3640     }
3641
3642     // This causes the default ~AllLoggedTypes() to be called, and thus
3643     // ~AllLoggedTypesHash() to be called
3644     delete pAllLoggedTypes;
3645     *ppAllLoggedTypes = NULL;
3646 }
3647
3648 //---------------------------------------------------------------------------------------
3649 //
3650 // Called from shutdown to give us the opportunity to dump any sampled object allocation
3651 // information before the process shuts down.
3652 //
3653
3654 // static
3655 VOID ETW::TypeSystemLog::FlushObjectAllocationEvents()
3656 {
3657     CONTRACTL
3658     {
3659         NOTHROW;
3660         GC_TRIGGERS;
3661         MODE_ANY;
3662         CAN_TAKE_LOCK;
3663     }
3664     CONTRACTL_END;
3665
3666     // If logging is not enabled, then we don't need to do any work.
3667     if (!(s_fHeapAllocLowEventEnabledNow || s_fHeapAllocHighEventEnabledNow))
3668     {
3669         return;
3670     }
3671
3672     AllLoggedTypes * pThreadAllLoggedTypes = NULL;
3673     Thread * pThread = NULL;
3674
3675     // Get the thread store lock.
3676     ThreadStoreLockHolder tsl;
3677
3678     // Iterate over each thread and log any un-logged allocations.
3679     while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
3680     {
3681         pThreadAllLoggedTypes = pThread->GetAllocationSamplingTable();
3682         if (pThreadAllLoggedTypes == NULL)
3683         {
3684             continue;
3685         }
3686
3687         DWORD dwAllocsSkippedForSample;
3688         SIZE_T cbIgnoredSizeForSample;
3689
3690         // Iterate over each module.
3691         AllLoggedTypesHash * pLoggedTypesHash = &pThreadAllLoggedTypes->allLoggedTypesHash;
3692         for (AllLoggedTypesHash::Iterator iter = pLoggedTypesHash->Begin();
3693             iter != pLoggedTypesHash->End();
3694             ++iter)
3695         {
3696             // Iterate over each type in the module.
3697             LoggedTypesFromModule * pLoggedTypesFromModule = *iter;
3698             LoggedTypesFromModuleHash * pLoggedTypesFromModuleHash = &pLoggedTypesFromModule->loggedTypesFromModuleHash;
3699             for (LoggedTypesFromModuleHash::Iterator typeIter = pLoggedTypesFromModuleHash->Begin();
3700                 typeIter != pLoggedTypesFromModuleHash->End();
3701                 ++typeIter)
3702             {
3703                 dwAllocsSkippedForSample = typeIter->dwAllocsSkippedForSample;
3704                 cbIgnoredSizeForSample = typeIter->cbIgnoredSizeForSample;
3705
3706                 // Only write the event if there were allocations that have not been logged.
3707                 if (dwAllocsSkippedForSample > 0 || cbIgnoredSizeForSample > 0)
3708                 {
3709                     // Write the event based on which keyword was specified when ETW was configured.
3710                     if (s_fHeapAllocHighEventEnabledNow)
3711                     {
3712                         FireEtwGCSampledObjectAllocationHigh(NULL, (LPVOID) typeIter->th.AsTAddr(), dwAllocsSkippedForSample, cbIgnoredSizeForSample, GetClrInstanceId());
3713                     }
3714                     else
3715                     {
3716                         FireEtwGCSampledObjectAllocationLow(NULL, (LPVOID) typeIter->th.AsTAddr(), dwAllocsSkippedForSample, cbIgnoredSizeForSample, GetClrInstanceId());
3717                     }
3718                 }
3719             }
3720         }
3721     }
3722 }
3723
3724 //---------------------------------------------------------------------------------------
3725 //
3726 // Whenever we detect that the Types keyword is off, this gets called. This eliminates the
3727 // global hash tables that tracked which types were logged (if the hash tables had been created
3728 // previously). If type events are turned back on later, we'll re-log them all as we
3729 // encounter them.  Thread local hash tables are destroyed in the Cleanup method, which is
3730 // called during GC to ensure that there aren't any races.
3731 //
3732
3733 // static
3734 VOID ETW::TypeSystemLog::OnTypesKeywordTurnedOff()
3735 {
3736     CONTRACTL
3737     {
3738         NOTHROW;
3739         GC_NOTRIGGER;
3740         MODE_ANY;
3741         CAN_TAKE_LOCK;
3742     }
3743     CONTRACTL_END;
3744
3745     // Take the global cache lock.
3746     CrstHolder _crst(GetHashCrst());
3747
3748     // Clean-up the global TypeHash if necessary.
3749     if (s_pAllLoggedTypes == NULL)
3750     {
3751         // Even if we don't increment the epoch, but we get into a situation where 
3752         // some per thread data has been allocated, it will be cleaned up during the
3753         // next GC because we are guaranteed that s_nEpoch has been incremented at
3754         // least once (to shutdown allocation sampling).
3755         return;
3756     }
3757
3758     // Destruct the global TypeHash
3759     DeleteTypeHashNoLock(&s_pAllLoggedTypes);
3760
3761     // Increment the epoch to signal the change to all threads.
3762     s_nEpoch++;
3763 }
3764
3765 //---------------------------------------------------------------------------------------
3766 //
3767 // Clean-up thread local type hashes.  This is called from within the GC to ensure that
3768 // there are no races.  All threads are suspended when this is called.
3769 //
3770
3771 // static
3772 VOID ETW::TypeSystemLog::Cleanup()
3773 {
3774     CONTRACTL
3775     {
3776         NOTHROW;
3777         GC_NOTRIGGER;
3778         MODE_ANY;
3779     }
3780     CONTRACTL_END;
3781
3782     // If allocation sampling is enabled, bail here so that we don't delete
3783     // any of the thread local state.
3784     if (ETW_TRACING_CATEGORY_ENABLED(
3785         MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3786         TRACE_LEVEL_INFORMATION, 
3787         CLR_TYPE_KEYWORD))
3788     {
3789         return;
3790     }
3791
3792     // If logging is disabled but the epoch has not been incremented,
3793     // we haven't ever turned on allocation sampling, so there is nothing
3794     // to clean-up.
3795     if(s_nEpoch <= 0)
3796     {
3797         return;
3798     }
3799
3800     // Iterate over each thread and destruct the per thread caches
3801     AllLoggedTypes * pThreadAllLoggedTypes = NULL;
3802     Thread * pThread = NULL;
3803     while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
3804     {
3805         pThreadAllLoggedTypes = pThread->GetAllocationSamplingTable();
3806         if(pThreadAllLoggedTypes == NULL)
3807         {
3808             continue;
3809         }
3810
3811         // Destruct each of the thread local TypesHashes
3812         DeleteTypeHashNoLock(&pThreadAllLoggedTypes);
3813
3814         // Set the thread type hash pointer to NULL
3815         pThread->SetAllocationSamplingTable(NULL);
3816     }
3817 }
3818
3819
3820 /****************************************************************************/
3821 /* Called when ETW is turned ON on an existing process and ModuleRange events are to
3822      be fired */
3823 /****************************************************************************/
3824 VOID ETW::EnumerationLog::ModuleRangeRundown()
3825 {
3826     CONTRACTL {
3827         NOTHROW;
3828         GC_TRIGGERS;
3829     } CONTRACTL_END;
3830
3831     EX_TRY
3832     {
3833         if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, 
3834                                          TRACE_LEVEL_INFORMATION, 
3835                                          CLR_PERFTRACK_PRIVATE_KEYWORD))
3836         {
3837             ETW::EnumerationLog::EnumerationHelper(NULL, NULL, ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoadPrivate);
3838         }
3839     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
3840 }
3841
3842
3843 /****************************************************************************/
3844 /* Called when ETW is turned ON on an existing process */
3845 /****************************************************************************/
3846 VOID ETW::EnumerationLog::StartRundown()
3847 {
3848     CONTRACTL {
3849         NOTHROW;
3850         GC_TRIGGERS;
3851     } CONTRACTL_END;
3852
3853     EX_TRY
3854     {
3855         BOOL bIsArmRundownEnabled = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
3856                                                                  TRACE_LEVEL_INFORMATION,
3857                                                                  CLR_RUNDOWNAPPDOMAINRESOURCEMANAGEMENT_KEYWORD);
3858         BOOL bIsPerfTrackRundownEnabled = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
3859                                                                  TRACE_LEVEL_INFORMATION,
3860                                                                  CLR_RUNDOWNPERFTRACK_KEYWORD);
3861         BOOL bIsThreadingRundownEnabled = ETW_TRACING_CATEGORY_ENABLED(
3862             MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
3863             TRACE_LEVEL_INFORMATION,
3864             CLR_RUNDOWNTHREADING_KEYWORD);
3865     
3866         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
3867                                         TRACE_LEVEL_INFORMATION, 
3868                                         CLR_RUNDOWNJIT_KEYWORD) 
3869            ||
3870            ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
3871                                         TRACE_LEVEL_INFORMATION, 
3872                                         CLR_RUNDOWNLOADER_KEYWORD) 
3873            ||
3874            IsRundownNgenKeywordEnabledAndNotSuppressed()
3875            ||
3876            ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
3877                                         TRACE_LEVEL_INFORMATION, 
3878                                         CLR_RUNDOWNJITTEDMETHODILTONATIVEMAP_KEYWORD)
3879            ||
3880            bIsArmRundownEnabled
3881            ||
3882            bIsPerfTrackRundownEnabled
3883            ||
3884            bIsThreadingRundownEnabled)
3885         {
3886             // begin marker event will go to the rundown provider
3887             FireEtwDCStartInit_V1(GetClrInstanceId());
3888
3889             // The rundown flag is expected to be checked in the caller, so no need to check here again
3890             DWORD enumerationOptions=ETW::EnumerationLog::EnumerationStructs::None;
3891             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
3892                                             TRACE_LEVEL_INFORMATION, 
3893                                             CLR_RUNDOWNLOADER_KEYWORD))
3894             {
3895                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart;
3896             }
3897             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
3898                                             TRACE_LEVEL_INFORMATION, 
3899                                             CLR_RUNDOWNJIT_KEYWORD))
3900             {
3901                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::JitMethodDCStart;
3902             }
3903             if(IsRundownNgenKeywordEnabledAndNotSuppressed())
3904             {
3905                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::NgenMethodDCStart;
3906             }
3907             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
3908                                             TRACE_LEVEL_INFORMATION, 
3909                                             CLR_RUNDOWNJITTEDMETHODILTONATIVEMAP_KEYWORD))
3910             {
3911                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::MethodDCStartILToNativeMap;
3912             }
3913             if(bIsPerfTrackRundownEnabled)
3914             {
3915                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCStart;
3916             }
3917
3918             ETW::EnumerationLog::EnumerationHelper(NULL, NULL, enumerationOptions);
3919             
3920             if (bIsArmRundownEnabled)
3921             {
3922                 // When an ETW event consumer asks for ARM rundown, that not only enables
3923                 // the ETW events, but also causes some minor behavioral changes in the
3924                 // CLR, such as gathering CPU usage baselines for each thread right now,
3925                 // and also gathering resource usage information later on (keyed off of
3926                 // g_fEnableARM, which we'll set right now).
3927                 EnableARM();
3928             }
3929
3930             if (bIsArmRundownEnabled || bIsThreadingRundownEnabled)
3931             {
3932                 SendThreadRundownEvent();
3933             }
3934
3935             // end marker event will go to the rundown provider
3936             FireEtwDCStartComplete_V1(GetClrInstanceId());
3937         }
3938     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
3939 }
3940
3941 //---------------------------------------------------------------------------------------
3942 //
3943 // Simple helper to convert the currently active keywords on the runtime provider into a
3944 // bitmask of enumeration options as defined in ETW::EnumerationLog::EnumerationStructs
3945 //
3946 // Return Value:
3947 //      ETW::EnumerationLog::EnumerationStructs bitmask corresponding to the currently
3948 //      active keywords on the runtime provider
3949 //
3950
3951 // static
3952 DWORD ETW::EnumerationLog::GetEnumerationOptionsFromRuntimeKeywords()
3953 {
3954     LIMITED_METHOD_CONTRACT;
3955
3956     DWORD enumerationOptions=ETW::EnumerationLog::EnumerationStructs::None;
3957     if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3958         TRACE_LEVEL_INFORMATION, 
3959         CLR_LOADER_KEYWORD))
3960     {
3961         enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload;
3962     }
3963     if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3964         TRACE_LEVEL_INFORMATION, 
3965         CLR_JIT_KEYWORD) &&
3966         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3967         TRACE_LEVEL_INFORMATION, 
3968         CLR_ENDENUMERATION_KEYWORD))
3969     {
3970         enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::JitMethodUnload;
3971     }
3972     if(IsRuntimeNgenKeywordEnabledAndNotSuppressed() &&
3973         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
3974         TRACE_LEVEL_INFORMATION, 
3975         CLR_ENDENUMERATION_KEYWORD))
3976     {
3977         enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::NgenMethodUnload;
3978     }
3979
3980     return enumerationOptions;
3981 }
3982
3983 //---------------------------------------------------------------------------------------
3984 //
3985 // Executes a flavor of rundown initiated by a CAPTURE_STATE request to
3986 // code:#EtwCallback.  CAPTURE_STATE is the "ETW-sanctioned" way of performing a
3987 // rundown, whereas the CLR's rundown provider was *our* version of this, implemented
3988 // before CAPTURE_STATE was standardized.
3989 // 
3990 // When doing a CAPTURE_STATE, the CLR rundown provider is completely unused.  Instead,
3991 // we pay attention to the runtime keywords active at the time the CAPTURE_STATE was
3992 // requested, and enumerate through the appropriate objects (AppDomains, assemblies,
3993 // modules, types, methods, threads) and send runtime events for each of them.
3994 //
3995 // CAPTURE_STATE is intended to be used primarily by PerfTrack.  Implementing this form
3996 // of rundown allows PerfTrack to be blissfully unaware of the CLR's rundown provider.
3997 // 
3998
3999 // static
4000 VOID ETW::EnumerationLog::EnumerateForCaptureState()
4001 {
4002     CONTRACTL 
4003     {
4004         NOTHROW;
4005         GC_TRIGGERS;
4006     }
4007     CONTRACTL_END;
4008
4009     EX_TRY
4010     {
4011         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, KEYWORDZERO))
4012         {
4013             DWORD enumerationOptions = GetEnumerationOptionsFromRuntimeKeywords();
4014
4015             // Send unload events for all remaining domains, including shared domain and
4016             // default domain.
4017             ETW::EnumerationLog::EnumerationHelper(NULL /* module filter */, NULL /* domain filter */, enumerationOptions);
4018
4019             // Send thread created events for all currently active threads, if requested
4020             if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
4021                                                                  TRACE_LEVEL_INFORMATION,
4022                                                                  CLR_THREADING_KEYWORD))
4023             {
4024                 SendThreadRundownEvent();
4025             }
4026         }
4027     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
4028 }
4029
4030 /**************************************************************************************/
4031 /* Called when ETW is turned OFF on an existing process .Will be used by the controller for end rundown*/
4032 /**************************************************************************************/
4033 VOID ETW::EnumerationLog::EndRundown()
4034 {
4035     CONTRACTL {
4036         NOTHROW;
4037         GC_TRIGGERS;
4038     } CONTRACTL_END;
4039
4040     EX_TRY
4041     {
4042         BOOL bIsPerfTrackRundownEnabled = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
4043                                                                  TRACE_LEVEL_INFORMATION,
4044                                                                  CLR_RUNDOWNPERFTRACK_KEYWORD);
4045         BOOL bIsThreadingRundownEnabled = ETW_TRACING_CATEGORY_ENABLED(
4046             MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
4047             TRACE_LEVEL_INFORMATION,
4048             CLR_RUNDOWNTHREADING_KEYWORD);
4049         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4050                                         TRACE_LEVEL_INFORMATION, 
4051                                         CLR_RUNDOWNJIT_KEYWORD) 
4052            ||
4053            ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4054                                         TRACE_LEVEL_INFORMATION, 
4055                                         CLR_RUNDOWNLOADER_KEYWORD) 
4056            ||
4057            IsRundownNgenKeywordEnabledAndNotSuppressed()
4058            ||
4059            ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4060                                         TRACE_LEVEL_INFORMATION, 
4061                                         CLR_RUNDOWNJITTEDMETHODILTONATIVEMAP_KEYWORD)
4062            ||
4063            bIsPerfTrackRundownEnabled
4064            ||
4065            bIsThreadingRundownEnabled
4066         )
4067         {
4068             // begin marker event will go to the rundown provider
4069             FireEtwDCEndInit_V1(GetClrInstanceId());
4070
4071             // The rundown flag is expected to be checked in the caller, so no need to check here again
4072             DWORD enumerationOptions=ETW::EnumerationLog::EnumerationStructs::None;
4073             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4074                                             TRACE_LEVEL_INFORMATION, 
4075                                             CLR_RUNDOWNLOADER_KEYWORD))
4076             {
4077                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd;
4078             }
4079             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4080                                             TRACE_LEVEL_INFORMATION, 
4081                                             CLR_RUNDOWNJIT_KEYWORD))
4082             {
4083                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::JitMethodDCEnd;
4084             }
4085             if(IsRundownNgenKeywordEnabledAndNotSuppressed())
4086             {
4087                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::NgenMethodDCEnd;
4088             }
4089             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4090                                             TRACE_LEVEL_INFORMATION, 
4091                                             CLR_RUNDOWNJITTEDMETHODILTONATIVEMAP_KEYWORD))
4092             {
4093                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::MethodDCEndILToNativeMap;
4094             }
4095             if(bIsPerfTrackRundownEnabled)
4096             {
4097                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCEnd;
4098             }
4099
4100             ETW::EnumerationLog::EnumerationHelper(NULL, NULL, enumerationOptions);
4101
4102             if (bIsThreadingRundownEnabled)
4103             {
4104                 SendThreadRundownEvent();
4105             }
4106
4107             // end marker event will go to the rundown provider
4108             FireEtwDCEndComplete_V1(GetClrInstanceId());
4109         }
4110     } EX_CATCH { 
4111         STRESS_LOG1(LF_ALWAYS, LL_ERROR, "Exception during Rundown Enumeration, EIP of last AV = %p", g_LastAccessViolationEIP);
4112     } EX_END_CATCH(SwallowAllExceptions);
4113 }
4114
4115 // #Registration
4116 /*++
4117
4118 Routine Description:
4119
4120     Registers provider with ETW tracing framework. 
4121     This function should not be called more than once, on 
4122     Dll Process attach only. 
4123     Not thread safe.    
4124
4125 Arguments:
4126     none
4127
4128 Return Value:
4129     Returns the return value from RegisterTraceGuids or EventRegister. 
4130
4131 --*/
4132
4133 void InitializeEventTracing()
4134 {
4135     CONTRACTL
4136     {
4137         THROWS;
4138         GC_TRIGGERS;
4139         MODE_ANY;
4140     }
4141     CONTRACTL_END;
4142
4143     // Do startup-only initialization of any state required by the ETW classes before
4144     // events can be fired
4145     HRESULT hr = ETW::TypeSystemLog::PreRegistrationInit();
4146     if (FAILED(hr))
4147         return;
4148
4149 #if !defined(FEATURE_PAL)
4150     // Register CLR providers with the OS
4151     if (g_pEtwTracer == NULL)
4152     {
4153         NewHolder <ETW::CEtwTracer> tempEtwTracer (new (nothrow) ETW::CEtwTracer());
4154         if (tempEtwTracer != NULL && tempEtwTracer->Register () == ERROR_SUCCESS)
4155             g_pEtwTracer = tempEtwTracer.Extract ();
4156     }
4157 #endif
4158
4159     g_nClrInstanceId = GetRuntimeId() & 0x0000FFFF; // This will give us duplicate ClrInstanceId after UINT16_MAX
4160
4161     // Any classes that need some initialization to happen after we've registered the
4162     // providers can do so now
4163     ETW::TypeSystemLog::PostRegistrationInit();
4164 }
4165
4166 // Plumbing to funnel event pipe callbacks and ETW callbacks together into a single common
4167 // handler, for the purposes of informing the GC of changes to the event state.
4168 //
4169 // There is one callback for every EventPipe provider and one for all of ETW. The reason
4170 // for this is that ETW passes the registration handle of the provider that was enabled
4171 // as a field on the "CallbackContext" field of the callback, while EventPipe passes null
4172 // unless another token is given to it when the provider is constructed. In the absence of
4173 // a suitable token, this implementation has a different callback for every EventPipe provider
4174 // that ultimately funnels them all into a common handler.
4175
4176 #if defined(FEATURE_PAL)
4177 // CLR_GCHEAPCOLLECT_KEYWORD is defined by the generated ETW manifest on Windows.
4178 // On non-Windows, we need to make sure that this is defined.  Given that we can't change
4179 // the value due to compatibility, we specify it here rather than generating defines based on the manifest.
4180 #define CLR_GCHEAPCOLLECT_KEYWORD 0x800000
4181 #endif // defined(FEATURE_PAL)
4182
4183 // CallbackProviderIndex provides a quick identification of which provider triggered the
4184 // ETW callback.
4185 enum CallbackProviderIndex
4186 {
4187     DotNETRuntime = 0,
4188     DotNETRuntimeRundown = 1,
4189     DotNETRuntimeStress = 2,
4190     DotNETRuntimePrivate = 3
4191 };
4192
4193 // Common handler for all ETW or EventPipe event notifications. Based on the provider that
4194 // was enabled/disabled, this implementation forwards the event state change onto GCHeapUtilities
4195 // which will inform the GC to update its local state about what events are enabled.
4196 VOID EtwCallbackCommon(
4197     CallbackProviderIndex ProviderIndex,
4198     ULONG ControlCode,
4199     UCHAR Level,
4200     ULONGLONG MatchAnyKeyword,
4201     PVOID pFilterData)
4202 {
4203     LIMITED_METHOD_CONTRACT;
4204
4205     bool bIsPublicTraceHandle = ProviderIndex == DotNETRuntime;
4206 #if !defined(FEATURE_PAL)
4207     static_assert(GCEventLevel_None == TRACE_LEVEL_NONE, "GCEventLevel_None value mismatch");
4208     static_assert(GCEventLevel_Fatal == TRACE_LEVEL_FATAL, "GCEventLevel_Fatal value mismatch");
4209     static_assert(GCEventLevel_Error == TRACE_LEVEL_ERROR, "GCEventLevel_Error value mismatch");
4210     static_assert(GCEventLevel_Warning == TRACE_LEVEL_WARNING, "GCEventLevel_Warning mismatch");
4211     static_assert(GCEventLevel_Information == TRACE_LEVEL_INFORMATION, "GCEventLevel_Information mismatch");
4212     static_assert(GCEventLevel_Verbose == TRACE_LEVEL_VERBOSE, "GCEventLevel_Verbose mismatch");
4213 #endif // !defined(FEATURE_PAL)
4214     GCEventKeyword keywords = static_cast<GCEventKeyword>(MatchAnyKeyword);
4215     GCEventLevel level = static_cast<GCEventLevel>(Level);
4216     GCHeapUtilities::RecordEventStateChange(bIsPublicTraceHandle, keywords, level);
4217
4218     // Special check for the runtime provider's GCHeapCollectKeyword.  Profilers
4219     // flick this to force a full GC.
4220     if (g_fEEStarted && !g_fEEShutDown && bIsPublicTraceHandle &&
4221         ((MatchAnyKeyword & CLR_GCHEAPCOLLECT_KEYWORD) != 0))
4222     {
4223         // Profilers may (optionally) specify extra data in the filter parameter
4224         // to log with the GCStart event.
4225         LONGLONG l64ClientSequenceNumber = 0;
4226 #if !defined(FEATURE_PAL)
4227         PEVENT_FILTER_DESCRIPTOR FilterData = (PEVENT_FILTER_DESCRIPTOR)pFilterData;
4228         if ((FilterData != NULL) &&
4229            (FilterData->Type == 1) &&
4230            (FilterData->Size == sizeof(l64ClientSequenceNumber)))
4231         {
4232             l64ClientSequenceNumber = *(LONGLONG *) (FilterData->Ptr);
4233         }
4234 #endif // !defined(FEATURE_PAL)
4235         ETW::GCLog::ForceGC(l64ClientSequenceNumber);
4236     }
4237 }
4238
4239 // Individual callbacks for each EventPipe provider.
4240
4241 VOID EventPipeEtwCallbackDotNETRuntimeStress(
4242     _In_ LPCGUID SourceId,
4243     _In_ ULONG ControlCode,
4244     _In_ UCHAR Level,
4245     _In_ ULONGLONG MatchAnyKeyword,
4246     _In_ ULONGLONG MatchAllKeyword,
4247     _In_opt_ PVOID FilterData,
4248     _Inout_opt_ PVOID CallbackContext)
4249 {
4250     LIMITED_METHOD_CONTRACT;
4251
4252     EtwCallbackCommon(DotNETRuntimeStress, ControlCode, Level, MatchAnyKeyword, FilterData);
4253 }
4254
4255 VOID EventPipeEtwCallbackDotNETRuntime(
4256     _In_ LPCGUID SourceId,
4257     _In_ ULONG ControlCode,
4258     _In_ UCHAR Level,
4259     _In_ ULONGLONG MatchAnyKeyword,
4260     _In_ ULONGLONG MatchAllKeyword,
4261     _In_opt_ PVOID FilterData,
4262     _Inout_opt_ PVOID CallbackContext)
4263 {
4264     LIMITED_METHOD_CONTRACT;
4265
4266     EtwCallbackCommon(DotNETRuntime, ControlCode, Level, MatchAnyKeyword, FilterData);
4267 }
4268
4269 VOID EventPipeEtwCallbackDotNETRuntimeRundown(
4270     _In_ LPCGUID SourceId,
4271     _In_ ULONG ControlCode,
4272     _In_ UCHAR Level,
4273     _In_ ULONGLONG MatchAnyKeyword,
4274     _In_ ULONGLONG MatchAllKeyword,
4275     _In_opt_ PVOID FilterData,
4276     _Inout_opt_ PVOID CallbackContext)
4277 {
4278     LIMITED_METHOD_CONTRACT;
4279
4280     EtwCallbackCommon(DotNETRuntimeRundown, ControlCode, Level, MatchAnyKeyword, FilterData);
4281 }
4282
4283 VOID EventPipeEtwCallbackDotNETRuntimePrivate(
4284     _In_ LPCGUID SourceId,
4285     _In_ ULONG ControlCode,
4286     _In_ UCHAR Level,
4287     _In_ ULONGLONG MatchAnyKeyword,
4288     _In_ ULONGLONG MatchAllKeyword,
4289     _In_opt_ PVOID FilterData,
4290     _Inout_opt_ PVOID CallbackContext)
4291 {
4292     WRAPPER_NO_CONTRACT;
4293
4294     EtwCallbackCommon(DotNETRuntimePrivate, ControlCode, Level, MatchAnyKeyword, FilterData);
4295 }
4296
4297
4298 #if !defined(FEATURE_PAL)
4299 HRESULT ETW::CEtwTracer::Register()
4300 {
4301     WRAPPER_NO_CONTRACT;
4302
4303     EventRegisterMicrosoft_Windows_DotNETRuntime();
4304     EventRegisterMicrosoft_Windows_DotNETRuntimePrivate();
4305     EventRegisterMicrosoft_Windows_DotNETRuntimeRundown();
4306
4307     // Stress Log ETW events are available only on the desktop version of the runtime
4308
4309     MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context.RegistrationHandle = Microsoft_Windows_DotNETRuntimeHandle;
4310     MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context.RegistrationHandle = Microsoft_Windows_DotNETRuntimePrivateHandle;
4311     MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context.RegistrationHandle = Microsoft_Windows_DotNETRuntimeRundownHandle;
4312
4313     return S_OK;
4314 }
4315
4316 // #Unregistration
4317 /*++
4318
4319 Routine Description:
4320         Unregisters the provider from ETW. This function
4321         should only be called once from DllMain Detach process.
4322         Not thread safe.
4323
4324 Arguments:
4325        none
4326
4327 Return Value:
4328        Returns ERROR_SUCCESS
4329
4330 --*/
4331 HRESULT ETW::CEtwTracer::UnRegister() 
4332 {
4333     LIMITED_METHOD_CONTRACT;
4334     EventUnregisterMicrosoft_Windows_DotNETRuntime();
4335     EventUnregisterMicrosoft_Windows_DotNETRuntimePrivate();
4336     EventUnregisterMicrosoft_Windows_DotNETRuntimeRundown();
4337     return S_OK;
4338 }
4339
4340 extern "C"
4341 {
4342     ETW_INLINE
4343     VOID EtwCallout(REGHANDLE RegHandle,
4344                     PCEVENT_DESCRIPTOR Descriptor,
4345                     ULONG ArgumentCount,
4346                     PEVENT_DATA_DESCRIPTOR EventData)
4347     {
4348         WRAPPER_NO_CONTRACT;
4349         UINT8 providerIndex = 0;
4350         if(RegHandle == Microsoft_Windows_DotNETRuntimeHandle) {
4351             providerIndex = 0;
4352         } else if(RegHandle == Microsoft_Windows_DotNETRuntimeRundownHandle) {
4353             providerIndex = 1;
4354         } else if(RegHandle == Microsoft_Windows_DotNETRuntimeStressHandle) {
4355             providerIndex = 2;
4356         } else if(RegHandle == Microsoft_Windows_DotNETRuntimePrivateHandle) {
4357             providerIndex = 3;
4358         } else {
4359             _ASSERTE(!"Provider not one of Runtime, Rundown, Private and Stress");
4360             return;
4361         }
4362
4363         // stacks are supposed to be fired for only the events with a bit set in the etwStackSupportedEvents bitmap
4364         if(((etwStackSupportedEvents[providerIndex][Descriptor->Id/8]) & 
4365             (1<<(Descriptor->Id%8))) != 0)
4366         {
4367             if(RegHandle == Microsoft_Windows_DotNETRuntimeHandle) {                
4368                 ETW::SamplingLog::SendStackTrace(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, &CLRStackWalk, &CLRStackId);
4369             } else if(RegHandle == Microsoft_Windows_DotNETRuntimeRundownHandle) {
4370                 ETW::SamplingLog::SendStackTrace(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, &CLRStackWalkDCStart, &CLRStackRundownId);
4371             } else if(RegHandle == Microsoft_Windows_DotNETRuntimePrivateHandle) {
4372                 ETW::SamplingLog::SendStackTrace(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, &CLRStackWalkPrivate, &CLRStackPrivateId);
4373             } else if(RegHandle == Microsoft_Windows_DotNETRuntimeStressHandle) {
4374                 ETW::SamplingLog::SendStackTrace(MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_Context, &CLRStackWalkStress, &CLRStackStressId);
4375             }
4376         }
4377     }
4378 }
4379
4380 extern "C"
4381 {
4382     // #EtwCallback:
4383     // During the build, MC generates the code to register our provider, and to register
4384     // our ETW callback. (This is buried under Intermediates, in a path like
4385     // Intermediate\clr\corguids.nativeproj_1723354836\obj1c\x86\ClrEtwAll.h.) The ETW
4386     // callback is also generated for us by MC. But we can hook into this generated
4387     // callback by #defining MCGEN_PRIVATE_ENABLE_CALLBACK_V2 to be a call to this
4388     // function (EtwCallback), thus causing EtwCallback to get called after the
4389     // MC-generated code executes.
4390     // 
4391     // This callback function is called whenever an ETW session is enabled or disabled. A
4392     // callback function needs to be specified when the provider is registered. C style
4393     // callback wrappers are needed during event registration. To handle the callback
4394     // action in this class, we pass "this" during provider registration and modify the
4395     // context to the relevant context in the C callback later.
4396     ETW_INLINE
4397     VOID EtwCallback(
4398         _In_ LPCGUID SourceId,
4399         _In_ ULONG ControlCode,
4400         _In_ UCHAR Level,
4401         _In_ ULONGLONG MatchAnyKeyword,
4402         _In_ ULONGLONG MatchAllKeyword,
4403         _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData,
4404         _Inout_opt_ PVOID CallbackContext)
4405     {
4406         CONTRACTL {
4407             NOTHROW;
4408             if(g_fEEStarted) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
4409             MODE_ANY;
4410             CAN_TAKE_LOCK;
4411             STATIC_CONTRACT_FAULT;
4412             SO_NOT_MAINLINE;
4413         } CONTRACTL_END;
4414
4415         // Mark that we are the special ETWRundown thread.  Currently all this does
4416         // is insure that AVs thrown in this thread are treated as normal exceptions.
4417         // This allows us to catch and swallow them.   We can do this because we have 
4418         // a reasonably strong belief that doing ETW Rundown does not change runtime state
4419         // and thus if an AV happens it is better to simply give up logging ETW and 
4420         // instead of terminating the process (which is what we would do normally)
4421         ClrFlsThreadTypeSwitch etwRundownThreadHolder(ThreadType_ETWRundownThread);
4422         PMCGEN_TRACE_CONTEXT context = (PMCGEN_TRACE_CONTEXT)CallbackContext;
4423
4424         BOOLEAN bIsPublicTraceHandle = (context->RegistrationHandle==Microsoft_Windows_DotNETRuntimeHandle);
4425
4426         BOOLEAN bIsPrivateTraceHandle = (context->RegistrationHandle==Microsoft_Windows_DotNETRuntimePrivateHandle);
4427
4428         BOOLEAN bIsRundownTraceHandle = (context->RegistrationHandle==Microsoft_Windows_DotNETRuntimeRundownHandle);
4429
4430         // EventPipeEtwCallback contains some GC eventing functionality shared between EventPipe and ETW.
4431         // Eventually, we'll want to merge these two codepaths whenever we can.
4432         CallbackProviderIndex providerIndex = DotNETRuntime;
4433         if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeHandle) {
4434             providerIndex = DotNETRuntime;
4435         } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeRundownHandle) {
4436             providerIndex = DotNETRuntimeRundown;
4437         } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeStressHandle) {
4438             providerIndex = DotNETRuntimeStress;
4439         } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimePrivateHandle) {
4440             providerIndex = DotNETRuntimePrivate;
4441         } else {
4442             assert(!"unknown registration handle");
4443             return;
4444         }
4445
4446         EtwCallbackCommon(providerIndex, ControlCode, Level, MatchAnyKeyword, FilterData);
4447
4448         // TypeSystemLog needs a notification when certain keywords are modified, so
4449         // give it a hook here.
4450         if (g_fEEStarted && !g_fEEShutDown && bIsPublicTraceHandle)
4451         {
4452             ETW::TypeSystemLog::OnKeywordsChanged();
4453         }
4454
4455         // A manifest based provider can be enabled to multiple event tracing sessions
4456         // As long as there is atleast 1 enabled session, IsEnabled will be TRUE
4457         // Since classic providers can be enabled to only a single session, 
4458         // IsEnabled will be TRUE when it is enabled and FALSE when disabled
4459         BOOL bEnabled = 
4460             ((ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER) || 
4461              (ControlCode == EVENT_CONTROL_CODE_CAPTURE_STATE));
4462         if(bEnabled)
4463         {
4464             if (bIsPrivateTraceHandle)
4465             {
4466                 ETW::GCLog::GCSettingsEvent();
4467                 if(g_fEEStarted && !g_fEEShutDown)
4468                 {
4469                     ETW::EnumerationLog::ModuleRangeRundown();
4470                 }
4471             }
4472
4473 #ifdef _TARGET_AMD64_
4474             // We only do this on amd64  (NOT ARM, because ARM uses frame based stack crawling)
4475             // If we have turned on the JIT keyword to the INFORMATION setting (needed to get JIT names) then
4476             // we assume that we also want good stack traces so we need to publish unwind information so
4477             // ETW can get at it
4478             if(bIsPublicTraceHandle && ETW_CATEGORY_ENABLED((*context), TRACE_LEVEL_INFORMATION, CLR_RUNDOWNJIT_KEYWORD))
4479                 UnwindInfoTable::PublishUnwindInfo(g_fEEStarted != FALSE);
4480 #endif
4481
4482             if(g_fEEStarted && !g_fEEShutDown && bIsRundownTraceHandle)
4483             {
4484                 // Fire the runtime information event
4485                 ETW::InfoLog::RuntimeInformation(ETW::InfoLog::InfoStructs::Callback);
4486
4487                 // Start and End Method/Module Rundowns
4488                 // Used to fire events that we missed since we started the controller after the process started
4489                 // flags for immediate start rundown
4490                 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4491                                                 TRACE_LEVEL_INFORMATION, 
4492                                                 CLR_RUNDOWNSTART_KEYWORD))
4493                     ETW::EnumerationLog::StartRundown();
4494
4495                 // flags delayed end rundown
4496                 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
4497                                                 TRACE_LEVEL_INFORMATION, 
4498                                                 CLR_RUNDOWNEND_KEYWORD))
4499                     ETW::EnumerationLog::EndRundown();
4500             }
4501
4502             if (g_fEEStarted && !g_fEEShutDown && (ControlCode == EVENT_CONTROL_CODE_CAPTURE_STATE))
4503             {
4504                 ETW::EnumerationLog::EnumerateForCaptureState();
4505             }
4506         }
4507 #ifdef FEATURE_COMINTEROP
4508         if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, CCWRefCountChange)) 
4509             g_pConfig->SetLogCCWRefCountChangeEnabled(bEnabled != 0);
4510 #endif // FEATURE_COMINTEROP
4511
4512     }
4513 }
4514 #endif // FEATURE_REDHAWK
4515
4516 #endif // FEATURE_PAL
4517 #ifndef FEATURE_REDHAWK
4518
4519 /****************************************************************************/
4520 /* This is called by the runtime when an exception is thrown */
4521 /****************************************************************************/
4522 VOID ETW::ExceptionLog::ExceptionThrown(CrawlFrame  *pCf, BOOL bIsReThrownException, BOOL bIsNewException)
4523 {
4524     CONTRACTL {
4525         NOTHROW;
4526         GC_TRIGGERS;
4527         PRECONDITION(GetThread() != NULL);
4528         PRECONDITION(GetThread()->GetThrowable() != NULL);
4529     } CONTRACTL_END;
4530
4531     if(!(bIsReThrownException || bIsNewException))
4532     {
4533         return;
4534     }
4535     if(!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionThrown_V1))
4536     {
4537         return;
4538     }
4539     EX_TRY
4540     {
4541         SString exceptionType(W(""));
4542         LPWSTR exceptionMessage = NULL;
4543         BOOL bIsCLSCompliant=FALSE, bIsCSE=FALSE, bIsNestedException=FALSE, bHasInnerException=FALSE;
4544         UINT16 exceptionFlags=0;
4545         PVOID exceptionEIP=0;
4546
4547         Thread *pThread = GetThread();
4548
4549         struct 
4550         {
4551             OBJECTREF exceptionObj;
4552             OBJECTREF innerExceptionObj;
4553             STRINGREF exceptionMessageRef;
4554         } gc;
4555         ZeroMemory(&gc, sizeof(gc));
4556         GCPROTECT_BEGIN(gc);
4557
4558         gc.exceptionObj = pThread->GetThrowable();
4559         gc.innerExceptionObj = ((EXCEPTIONREF)gc.exceptionObj)->GetInnerException();
4560
4561         ThreadExceptionState *pExState = pThread->GetExceptionState();
4562 #ifndef WIN64EXCEPTIONS
4563         PTR_ExInfo pExInfo = NULL;
4564 #else
4565         PTR_ExceptionTracker pExInfo = NULL;
4566 #endif //!WIN64EXCEPTIONS
4567         pExInfo = pExState->GetCurrentExceptionTracker();
4568         _ASSERTE(pExInfo != NULL);
4569         bIsNestedException = (pExInfo->GetPreviousExceptionTracker() != NULL);
4570         bIsCSE = (pExInfo->GetCorruptionSeverity() == ProcessCorrupting);
4571         bIsCLSCompliant = IsException((gc.exceptionObj)->GetMethodTable()) && 
4572                           ((gc.exceptionObj)->GetMethodTable() != MscorlibBinder::GetException(kRuntimeWrappedException));
4573
4574         // A rethrown exception is also a nested exception
4575         // but since we have a separate flag for it, lets unset the nested flag
4576         if(bIsReThrownException)
4577         {
4578             bIsNestedException = FALSE;
4579         }
4580         bHasInnerException = (gc.innerExceptionObj) != NULL;
4581
4582         exceptionFlags = ((bHasInnerException ? ETW::ExceptionLog::ExceptionStructs::HasInnerException : 0) |
4583                           (bIsNestedException ? ETW::ExceptionLog::ExceptionStructs::IsNestedException : 0) |
4584                           (bIsReThrownException ? ETW::ExceptionLog::ExceptionStructs::IsReThrownException : 0) |
4585                           (bIsCSE ? ETW::ExceptionLog::ExceptionStructs::IsCSE : 0) |
4586                           (bIsCLSCompliant ? ETW::ExceptionLog::ExceptionStructs::IsCLSCompliant : 0));
4587
4588         if (pCf->IsFrameless())
4589         {
4590 #ifndef _WIN64
4591             exceptionEIP = (PVOID)pCf->GetRegisterSet()->ControlPC;
4592 #else
4593             exceptionEIP = (PVOID)GetIP(pCf->GetRegisterSet()->pContext);
4594 #endif //!_WIN64
4595         }
4596         else
4597         {
4598             exceptionEIP = (PVOID)(pCf->GetFrame()->GetIP());
4599         }
4600
4601         // On platforms other than IA64, we are at the instruction after the faulting instruction
4602         // This check has been copied from StackTraceInfo::AppendElement
4603         if (!(pCf->HasFaulted() || pCf->IsIPadjusted()) && exceptionEIP != 0)
4604         {
4605             exceptionEIP = (PVOID)((UINT_PTR)exceptionEIP - 1);
4606         }
4607
4608         gc.exceptionMessageRef =  ((EXCEPTIONREF)gc.exceptionObj)->GetMessage();
4609         TypeHandle exceptionTypeHandle = (gc.exceptionObj)->GetTypeHandle();
4610         exceptionTypeHandle.GetName(exceptionType);
4611         WCHAR *exceptionTypeName = (WCHAR *)exceptionType.GetUnicode(); 
4612
4613         if(gc.exceptionMessageRef != NULL)
4614         {
4615             exceptionMessage = (gc.exceptionMessageRef)->GetBuffer();
4616         }
4617         
4618         HRESULT exceptionHRESULT = ((EXCEPTIONREF)gc.exceptionObj)->GetHResult();
4619
4620         FireEtwExceptionThrown_V1(exceptionTypeName,
4621                                   exceptionMessage,
4622                                   exceptionEIP,
4623                                   exceptionHRESULT,
4624                                   exceptionFlags,
4625                                   GetClrInstanceId());
4626         GCPROTECT_END();
4627     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
4628 }
4629
4630
4631 VOID ETW::ExceptionLog::ExceptionThrownEnd()
4632 {
4633     CONTRACTL{
4634         NOTHROW;
4635         GC_NOTRIGGER;
4636     } CONTRACTL_END;
4637
4638     if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionThrownStop))
4639     {
4640         return;
4641     }
4642
4643     FireEtwExceptionThrownStop();
4644 }
4645
4646 /****************************************************************************/
4647 /* This is called by the runtime when an exception is handled by the runtime */
4648 /****************************************************************************/
4649 VOID ETW::ExceptionLog::ExceptionCatchBegin(MethodDesc * pMethodDesc, PVOID pEntryEIP)
4650 {
4651     CONTRACTL{
4652         NOTHROW;
4653         GC_NOTRIGGER;
4654     } CONTRACTL_END;
4655
4656     if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionCatchStart))
4657     {
4658         return;
4659     }
4660
4661     EX_TRY
4662     {
4663         SString methodName;
4664         pMethodDesc->GetFullMethodInfo(methodName);
4665
4666         FireEtwExceptionCatchStart((uint64_t)pEntryEIP,
4667             (uint64_t)pMethodDesc,
4668             methodName.GetUnicode(),
4669             GetClrInstanceId());
4670
4671     } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
4672 }
4673
4674 VOID ETW::ExceptionLog::ExceptionCatchEnd()
4675 {
4676     CONTRACTL{
4677         NOTHROW;
4678         GC_NOTRIGGER;
4679     } CONTRACTL_END;
4680
4681     if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionCatchStop))
4682     {
4683         return;
4684     }
4685
4686     FireEtwExceptionCatchStop();
4687 }
4688
4689 VOID ETW::ExceptionLog::ExceptionFinallyBegin(MethodDesc * pMethodDesc, PVOID pEntryEIP)
4690 {
4691     CONTRACTL{
4692         NOTHROW;
4693         GC_NOTRIGGER;
4694     } CONTRACTL_END;
4695
4696     if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFinallyStart))
4697     {
4698         return;
4699     }
4700
4701     EX_TRY
4702     {
4703         SString methodName;
4704         pMethodDesc->GetFullMethodInfo(methodName);
4705      
4706         FireEtwExceptionFinallyStart((uint64_t)pEntryEIP,
4707             (uint64_t)pMethodDesc,
4708             methodName.GetUnicode(),
4709             GetClrInstanceId());
4710
4711     } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
4712 }
4713
4714 VOID ETW::ExceptionLog::ExceptionFinallyEnd()
4715 {
4716     CONTRACTL{
4717         NOTHROW;
4718         GC_NOTRIGGER;
4719     } CONTRACTL_END;
4720
4721     if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFinallyStop))
4722     {
4723         return;
4724     }
4725
4726     FireEtwExceptionFinallyStop();
4727 }
4728
4729 VOID ETW::ExceptionLog::ExceptionFilterBegin(MethodDesc * pMethodDesc, PVOID pEntryEIP)
4730 {
4731     CONTRACTL{
4732         NOTHROW;
4733         GC_NOTRIGGER;
4734     } CONTRACTL_END;
4735
4736     if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFilterStart))
4737     {
4738         return;
4739     }
4740
4741     EX_TRY
4742     {
4743         SString methodName;
4744         pMethodDesc->GetFullMethodInfo(methodName);
4745
4746         FireEtwExceptionFilterStart((uint64_t)pEntryEIP,
4747             (uint64_t)pMethodDesc,
4748             methodName.GetUnicode(),
4749             GetClrInstanceId());
4750
4751     } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
4752 }
4753
4754 VOID ETW::ExceptionLog::ExceptionFilterEnd()
4755 {
4756     CONTRACTL{
4757         NOTHROW;
4758         GC_NOTRIGGER;
4759     } CONTRACTL_END;
4760
4761     if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFilterStop))
4762     {
4763         return;
4764     }
4765
4766     FireEtwExceptionFilterStop();
4767 }
4768
4769 /****************************************************************************/
4770 /* This is called by the runtime when a domain is loaded */
4771 /****************************************************************************/
4772 VOID ETW::LoaderLog::DomainLoadReal(BaseDomain *pDomain, __in_opt LPWSTR wszFriendlyName)
4773 {
4774     CONTRACTL {
4775         NOTHROW;
4776         GC_TRIGGERS;
4777     } CONTRACTL_END;
4778
4779     EX_TRY
4780     {
4781         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
4782                                         TRACE_LEVEL_INFORMATION, 
4783                                         CLR_LOADER_KEYWORD))
4784         {
4785             DWORD dwEventOptions = ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad;
4786             ETW::LoaderLog::SendDomainEvent(pDomain, dwEventOptions, wszFriendlyName);
4787         }
4788     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
4789 }
4790
4791 /****************************************************************************/
4792 /* This is called by the runtime when an AppDomain is unloaded */
4793 /****************************************************************************/
4794 VOID ETW::LoaderLog::DomainUnload(AppDomain *pDomain)
4795 {
4796     CONTRACTL {
4797         NOTHROW;
4798         GC_TRIGGERS;
4799     } CONTRACTL_END;
4800
4801     EX_TRY
4802     {
4803         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
4804                                         TRACE_LEVEL_INFORMATION, 
4805                                         KEYWORDZERO))
4806         {
4807             DWORD enumerationOptions = ETW::EnumerationLog::GetEnumerationOptionsFromRuntimeKeywords();
4808
4809             // Domain unload also causes type unload events
4810             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
4811                                             TRACE_LEVEL_INFORMATION, 
4812                                             CLR_TYPE_KEYWORD))
4813             {
4814                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::TypeUnload;
4815             }
4816
4817             ETW::EnumerationLog::EnumerationHelper(NULL, pDomain, enumerationOptions);
4818         }
4819     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
4820 }
4821
4822 /****************************************************************************/
4823 /* This is called by the runtime when a LoaderAllocator is unloaded */
4824 /****************************************************************************/
4825 VOID ETW::LoaderLog::CollectibleLoaderAllocatorUnload(AssemblyLoaderAllocator *pLoaderAllocator)
4826 {
4827     CONTRACTL {
4828         NOTHROW;
4829         GC_TRIGGERS;
4830     } CONTRACTL_END;
4831
4832     EX_TRY
4833     {
4834         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
4835                                         TRACE_LEVEL_INFORMATION, 
4836                                         KEYWORDZERO))
4837         {
4838             DWORD enumerationOptions = ETW::EnumerationLog::GetEnumerationOptionsFromRuntimeKeywords();
4839
4840             // Collectible Loader Allocator unload also causes type unload events
4841             if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
4842                                             TRACE_LEVEL_INFORMATION, 
4843                                             CLR_TYPE_KEYWORD))
4844             {
4845                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::TypeUnload;
4846             }
4847
4848             ETW::EnumerationLog::IterateCollectibleLoaderAllocator(pLoaderAllocator, enumerationOptions);
4849         }
4850     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
4851 }
4852
4853 /****************************************************************************/
4854 /* This is called by the runtime when the runtime is loaded
4855    Function gets called by both the Callback mechanism and regular ETW events.
4856    Type is used to differentiate whether its a callback or a normal call*/
4857 /****************************************************************************/
4858 VOID ETW::InfoLog::RuntimeInformation(INT32 type) 
4859 {
4860     CONTRACTL {
4861         NOTHROW;
4862         GC_TRIGGERS;
4863     } CONTRACTL_END;
4864
4865     EX_TRY {
4866         if((type == ETW::InfoLog::InfoStructs::Normal && ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, RuntimeInformationStart)) 
4867             ||
4868            (type == ETW::InfoLog::InfoStructs::Callback && ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, RuntimeInformationDCStart))
4869           )
4870         {
4871             PCWSTR szDtraceOutput1=W(""),szDtraceOutput2=W("");
4872             UINT8 startupMode = 0;
4873             UINT startupFlags = 0;
4874             PathString dllPath;
4875             UINT8 Sku = 0;
4876             _ASSERTE(CLRHosted() || g_fEEHostedStartup || // CLR started through one of the Hosting API CLRHosted() returns true if CLR started through the V2 Interface while 
4877                                                           // g_fEEHostedStartup is true if CLR is hosted through the V1 API.
4878                      g_fEEComActivatedStartup ||          //CLR started as a COM object
4879                      g_fEEOtherStartup  );                //In case none of the 4 above mentioned cases are true for example ngen, ildasm then we asssume its a "other" startup
4880
4881             Sku = ETW::InfoLog::InfoStructs::CoreCLR;
4882         
4883             //version info for clr.dll
4884             USHORT vmMajorVersion = CLR_MAJOR_VERSION;
4885             USHORT vmMinorVersion = CLR_MINOR_VERSION;
4886             USHORT vmBuildVersion = CLR_BUILD_VERSION;
4887             USHORT vmQfeVersion = CLR_BUILD_VERSION_QFE;
4888
4889             //version info for mscorlib.dll
4890             USHORT bclMajorVersion = VER_ASSEMBLYMAJORVERSION;
4891             USHORT bclMinorVersion = VER_ASSEMBLYMINORVERSION;
4892             USHORT bclBuildVersion = VER_ASSEMBLYBUILD;
4893             USHORT bclQfeVersion = VER_ASSEMBLYBUILD_QFE;
4894
4895             LPCGUID comGUID=&g_EEComObjectGuid;
4896
4897             PCWSTR lpwszCommandLine = W("");
4898             
4899
4900
4901             // Determine the startupmode
4902             if (CLRHosted() || g_fEEHostedStartup)
4903             {
4904                 //Hosted CLR
4905                 startupMode = ETW::InfoLog::InfoStructs::HostedCLR;
4906             }
4907             else if(g_fEEComActivatedStartup) 
4908             {
4909                 //com activated
4910                 startupMode = ETW::InfoLog::InfoStructs::COMActivated;
4911             }
4912             else if(g_fEEOtherStartup)
4913             {
4914                 //startup type is other
4915                 startupMode = ETW::InfoLog::InfoStructs::Other;
4916             }
4917
4918           
4919             // if WszGetModuleFileName fails, we return an empty string
4920             if (!WszGetModuleFileName(GetCLRModule(), dllPath)) {
4921                 dllPath.Set(W("\0"));
4922             }
4923             
4924
4925             if(type == ETW::InfoLog::InfoStructs::Callback)
4926             {
4927                 FireEtwRuntimeInformationDCStart( GetClrInstanceId(),
4928                                                   Sku,
4929                                                   bclMajorVersion,
4930                                                   bclMinorVersion,
4931                                                   bclBuildVersion,
4932                                                   bclQfeVersion,
4933                                                   vmMajorVersion,
4934                                                   vmMinorVersion,
4935                                                   vmBuildVersion,
4936                                                   vmQfeVersion,
4937                                                   startupFlags,
4938                                                   startupMode,
4939                                                   lpwszCommandLine,
4940                                                   comGUID,
4941                                                   dllPath );
4942             }
4943             else
4944             {
4945                 FireEtwRuntimeInformationStart( GetClrInstanceId(),
4946                                                 Sku,
4947                                                 bclMajorVersion,
4948                                                 bclMinorVersion,
4949                                                 bclBuildVersion,
4950                                                 bclQfeVersion,
4951                                                 vmMajorVersion,
4952                                                 vmMinorVersion,
4953                                                 vmBuildVersion,
4954                                                 vmQfeVersion,
4955                                                 startupFlags,
4956                                                 startupMode,
4957                                                 lpwszCommandLine,
4958                                                 comGUID,
4959                                                 dllPath );
4960             }
4961         }
4962     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
4963 }
4964
4965 /* Fires ETW events every time a pdb is dynamically loaded.
4966 *
4967 * The ETW events correspond to sending parts of the pdb in roughly 
4968 * 64K sized chunks in order. Additional information sent is as follows:
4969 * ModuleID, TotalChunks, Size of Current Chunk, Chunk Number, CLRInstanceID
4970 *
4971 * Note: The current implementation does not support reflection.emit.
4972 * The method will silently return without firing an event.
4973 */
4974
4975 VOID ETW::CodeSymbolLog::EmitCodeSymbols(Module* pModule)
4976 {
4977 #if  !defined(FEATURE_PAL) //UNIXTODO: Enable EmitCodeSymbols
4978     CONTRACTL {
4979         NOTHROW;
4980         GC_NOTRIGGER;
4981         MODE_ANY;
4982         SO_NOT_MAINLINE;
4983     }
4984     CONTRACTL_END;
4985
4986
4987     EX_TRY {
4988         if (ETW_TRACING_CATEGORY_ENABLED(
4989                 MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
4990                 TRACE_LEVEL_VERBOSE,
4991                 CLR_CODESYMBOLS_KEYWORD))
4992         {
4993             if (pModule != NULL)
4994             {
4995                 UINT16 clrInstanceID = GetClrInstanceId();
4996                 UINT64 moduleID = (ModuleID)pModule;
4997                 DWORD length = 0;
4998                 // We silently exit if pdb is of length 0 instead of sending an event with no pdb bytes
4999                 if (CodeSymbolLog::GetInMemorySymbolsLength(pModule, &length) == S_OK && length > 0)
5000                 {
5001                     // The maximum data size allowed is 64K - (Size of the Event_Header) 
5002                     // Since the actual size of user data can only be determined at runtime
5003                     // we simplify the header size value to be 1000 bytes as a conservative 
5004                     // estmate. 
5005                     static const DWORD maxDataSize = 63000;
5006
5007                     ldiv_t qr = ldiv(length, maxDataSize);
5008
5009                     // We do not allow pdbs of size greater than 2GB for now, 
5010                     // so totalChunks should fit in 16 bits.
5011                     if (qr.quot < UINT16_MAX)
5012                     {
5013                         // If there are trailing bits in the last chunk, then increment totalChunks by 1
5014                         UINT16 totalChunks = (UINT16)(qr.quot + ((qr.rem != 0) ? 1 : 0));
5015                         NewArrayHolder<BYTE> chunk(new BYTE[maxDataSize]);
5016                         DWORD offset = 0;
5017                         for (UINT16 chunkNum = 0; offset < length; chunkNum++)
5018                         {
5019                             DWORD lengthRead = 0;
5020                             // We expect ReadInMemorySymbols to always return maxDataSize sized chunks
5021                             // Or it is the last chunk and it is less than maxDataSize.
5022                             CodeSymbolLog::ReadInMemorySymbols(pModule, offset, chunk, maxDataSize, &lengthRead);
5023
5024                             _ASSERTE(lengthRead == maxDataSize || // Either we are in the first to (n-1)th chunk
5025                                 (lengthRead < maxDataSize && chunkNum + 1 == totalChunks)); // Or we are in the last chunk
5026
5027                             FireEtwCodeSymbols(moduleID, totalChunks, chunkNum, lengthRead, chunk, clrInstanceID);
5028                             offset += lengthRead;
5029                         }
5030                     }
5031                 }
5032             }
5033         }
5034     } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
5035 #endif//  !defined(FEATURE_PAL)
5036 }
5037
5038 /* Returns the length of an in-memory symbol stream
5039 *
5040 * If the module has in-memory symbols the length of the stream will
5041 * be placed in pCountSymbolBytes. If the module doesn't have in-memory
5042 * symbols, *pCountSymbolBytes = 0
5043 *
5044 * Returns S_OK if the length could be determined (even if it is 0)
5045 *
5046 * Note: The current implementation does not support reflection.emit.
5047 * CORPROF_E_MODULE_IS_DYNAMIC will be returned in that case.
5048
5049 * //IMPORTANT NOTE: The desktop code outside the Project K branch 
5050 * contains copies of this function in the clr\src\vm\proftoeeinterfaceimpl.cpp
5051 * file of the desktop version corresponding to the profiler version
5052 * of this feature. Anytime that feature/code is ported to Project K 
5053 * the code below should be appropriately merged so as to avoid 
5054 * duplication. 
5055 */
5056
5057 HRESULT ETW::CodeSymbolLog::GetInMemorySymbolsLength(
5058     Module* pModule,
5059     DWORD* pCountSymbolBytes)
5060 {
5061     CONTRACTL
5062     {
5063         NOTHROW;
5064         GC_NOTRIGGER;
5065         MODE_ANY;
5066         SO_NOT_MAINLINE;
5067     }
5068     CONTRACTL_END;
5069
5070     HRESULT hr = S_OK;
5071     if (pCountSymbolBytes == NULL)
5072     {
5073         return E_INVALIDARG;
5074     }
5075     *pCountSymbolBytes = 0;
5076
5077     if (pModule == NULL)
5078     {
5079         return E_INVALIDARG;
5080     }
5081     if (pModule->IsBeingUnloaded())
5082     {
5083         return CORPROF_E_DATAINCOMPLETE;
5084     }
5085
5086     //This method would work fine on reflection.emit, but there would be no way to know
5087     //if some other thread was changing the size of the symbols before this method returned.
5088     //Adding events or locks to detect/prevent changes would make the scenario workable
5089     if (pModule->IsReflection())
5090     {
5091         return COR_PRF_MODULE_DYNAMIC;
5092     }
5093
5094     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
5095     if (pStream == NULL)
5096     {
5097         return S_OK;
5098     }
5099
5100     STATSTG SizeData = { 0 };
5101     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
5102     if (FAILED(hr))
5103     {
5104         return hr;
5105     }
5106     if (SizeData.cbSize.u.HighPart > 0)
5107     {
5108         return COR_E_OVERFLOW;
5109     }
5110     *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
5111
5112     return S_OK;
5113 }
5114
5115 /* Reads bytes from an in-memory symbol stream
5116 *
5117 * This function attempts to read countSymbolBytes of data starting at offset
5118 * symbolsReadOffset within the in-memory stream. The data will be copied into
5119 * pSymbolBytes which is expected to have countSymbolBytes of space available.
5120 * pCountSymbolsBytesRead contains the actual number of bytes read which
5121 * may be less than countSymbolBytes if the end of the stream is reached.
5122 *
5123 * Returns S_OK if a non-zero number of bytes were read.
5124 *
5125 * Note: The current implementation does not support reflection.emit.
5126 * CORPROF_E_MODULE_IS_DYNAMIC will be returned in that case.
5127 *
5128 * //IMPORTANT NOTE: The desktop code outside the Project K branch
5129 * contains copies of this function in the clr\src\vm\proftoeeinterfaceimpl.cpp
5130 * file of the desktop version corresponding to the profiler version
5131 * of this feature. Anytime that feature/code is ported to Project K
5132 * the code below should be appropriately merged so as to avoid
5133 * duplication.
5134
5135 */
5136
5137 HRESULT ETW::CodeSymbolLog::ReadInMemorySymbols(
5138     Module* pModule,
5139     DWORD symbolsReadOffset,
5140     BYTE* pSymbolBytes,
5141     DWORD countSymbolBytes,
5142     DWORD* pCountSymbolBytesRead)
5143 {
5144     CONTRACTL
5145     {
5146         NOTHROW;
5147         GC_NOTRIGGER;
5148         MODE_ANY;
5149         SO_NOT_MAINLINE;
5150     }
5151     CONTRACTL_END;
5152
5153     HRESULT hr = S_OK;
5154     if (pSymbolBytes == NULL)
5155     {
5156         return E_INVALIDARG;
5157     }
5158     if (pCountSymbolBytesRead == NULL)
5159     {
5160         return E_INVALIDARG;
5161     }
5162     *pCountSymbolBytesRead = 0;
5163
5164     if (pModule == NULL)
5165     {
5166         return E_INVALIDARG;
5167     }
5168     if (pModule->IsBeingUnloaded())
5169     {
5170         return CORPROF_E_DATAINCOMPLETE;
5171     }
5172
5173     //This method would work fine on reflection.emit, but there would be no way to know
5174     //if some other thread was changing the size of the symbols before this method returned.
5175     //Adding events or locks to detect/prevent changes would make the scenario workable
5176     if (pModule->IsReflection())
5177     {
5178         return COR_PRF_MODULE_DYNAMIC;
5179     }
5180
5181     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
5182     if (pStream == NULL)
5183     {
5184         return E_INVALIDARG;
5185     }
5186
5187     STATSTG SizeData = { 0 };
5188     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
5189     if (FAILED(hr))
5190     {
5191         return hr;
5192     }
5193     if (SizeData.cbSize.u.HighPart > 0)
5194     {
5195         return COR_E_OVERFLOW;
5196     }
5197     DWORD streamSize = SizeData.cbSize.u.LowPart;
5198     if (symbolsReadOffset >= streamSize)
5199     {
5200         return E_INVALIDARG;
5201     }
5202
5203     *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
5204     memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
5205
5206     return S_OK;
5207 }
5208
5209 /*******************************************************/
5210 /* This is called by the runtime when a method is jitted completely */
5211 /*******************************************************/
5212 VOID ETW::MethodLog::MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, SIZE_T pCode, ReJITID rejitID, BOOL bProfilerRejectedPrecompiledCode, BOOL bReadyToRunRejectedPrecompiledCode)
5213 {
5214     CONTRACTL {
5215         NOTHROW;
5216         GC_TRIGGERS;
5217     } CONTRACTL_END;
5218
5219     EX_TRY
5220     {
5221         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5222                                         TRACE_LEVEL_INFORMATION, 
5223                                         CLR_JIT_KEYWORD))
5224         {
5225             ETW::MethodLog::SendMethodEvent(pMethodDesc, ETW::EnumerationLog::EnumerationStructs::JitMethodLoad, TRUE, namespaceOrClassName, methodName, methodSignature, pCode, rejitID, bProfilerRejectedPrecompiledCode, bReadyToRunRejectedPrecompiledCode); 
5226         }
5227
5228         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5229                                         TRACE_LEVEL_INFORMATION, 
5230                                         CLR_JITTEDMETHODILTONATIVEMAP_KEYWORD))
5231         {
5232             // The call to SendMethodILToNativeMapEvent assumes that the debugger's lazy
5233             // data has already been initialized.
5234
5235             // g_pDebugInterface is initialized on startup on desktop CLR, regardless of whether a debugger
5236             // or profiler is loaded.  So it should always be available.
5237             _ASSERTE(g_pDebugInterface != NULL);
5238             g_pDebugInterface->InitializeLazyDataIfNecessary();
5239             
5240             ETW::MethodLog::SendMethodILToNativeMapEvent(pMethodDesc, ETW::EnumerationLog::EnumerationStructs::JitMethodILToNativeMap, pCode, rejitID);
5241         }
5242
5243     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5244 }
5245
5246 /*************************************************/
5247 /* This is called by the runtime when method jitting started */
5248 /*************************************************/
5249 VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature)
5250 {
5251     CONTRACTL {
5252         NOTHROW;
5253         GC_TRIGGERS;
5254         PRECONDITION(pMethodDesc != NULL);
5255     } CONTRACTL_END;
5256
5257     EX_TRY
5258     {
5259         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5260                                         TRACE_LEVEL_VERBOSE, 
5261                                         CLR_JIT_KEYWORD))
5262         {
5263             pMethodDesc->GetMethodInfo(*namespaceOrClassName, *methodName, *methodSignature);
5264             ETW::MethodLog::SendMethodJitStartEvent(pMethodDesc, namespaceOrClassName, methodName, methodSignature);
5265         }
5266     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5267 }
5268
5269 /**********************************************************************/
5270 /* This is called by the runtime when a single jit helper method with stub is initialized */
5271 /**********************************************************************/
5272 VOID ETW::MethodLog::StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pHelperName)
5273 {
5274     CONTRACTL {
5275         NOTHROW;
5276         GC_TRIGGERS;
5277         PRECONDITION(ullHelperStartAddress != 0);
5278     } CONTRACTL_END;
5279
5280     EX_TRY
5281     {
5282         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5283                                         TRACE_LEVEL_INFORMATION, 
5284                                         CLR_JIT_KEYWORD))
5285         {
5286             DWORD dwHelperSize=0;
5287             Stub::RecoverStubAndSize((TADDR)ullHelperStartAddress, &dwHelperSize);
5288             ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
5289         }
5290     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5291 }
5292
5293 /**********************************************************/
5294 /* This is called by the runtime when helpers with stubs are initialized */
5295 /**********************************************************/
5296 VOID ETW::MethodLog::StubsInitialized(PVOID *pHelperStartAddress, PVOID *pHelperNames, LONG lNoOfHelpers)
5297 {
5298     WRAPPER_NO_CONTRACT;
5299
5300     if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5301                                     TRACE_LEVEL_INFORMATION, 
5302                                     CLR_JIT_KEYWORD))
5303     {
5304         for(int i=0; i<lNoOfHelpers; i++)
5305         {
5306             if(pHelperStartAddress[i])
5307             {
5308                 StubInitialized((ULONGLONG)pHelperStartAddress[i], (LPCWSTR)pHelperNames[i]);
5309             }
5310         }
5311     }
5312 }
5313
5314 /****************************************************************************/
5315 /* This is called by the runtime when a dynamic method is destroyed */
5316 /****************************************************************************/
5317 VOID ETW::MethodLog::DynamicMethodDestroyed(MethodDesc *pMethodDesc)
5318 {
5319     CONTRACTL {
5320         NOTHROW;
5321         GC_TRIGGERS;
5322     } CONTRACTL_END;
5323
5324     EX_TRY
5325     {
5326         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5327                                         TRACE_LEVEL_INFORMATION, 
5328                                         CLR_JIT_KEYWORD))
5329             ETW::MethodLog::SendMethodEvent(pMethodDesc, ETW::EnumerationLog::EnumerationStructs::JitMethodUnload, TRUE);
5330     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5331 }
5332
5333 /****************************************************************************/
5334 /* This is called by the runtime when a ngen method is restored */
5335 /****************************************************************************/
5336 VOID ETW::MethodLog::MethodRestored(MethodDesc *pMethodDesc)
5337 {
5338     CONTRACTL {
5339         NOTHROW;
5340         GC_TRIGGERS;
5341     } CONTRACTL_END;
5342
5343     EX_TRY
5344     {
5345         if(IsRuntimeNgenKeywordEnabledAndNotSuppressed()
5346            && 
5347            ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5348                                         TRACE_LEVEL_INFORMATION, 
5349                                         CLR_STARTENUMERATION_KEYWORD))
5350         {
5351             ETW::MethodLog::SendMethodEvent(pMethodDesc, ETW::EnumerationLog::EnumerationStructs::NgenMethodLoad, FALSE);
5352         }
5353     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5354 }
5355
5356 /****************************************************************************/
5357 /* This is called by the runtime when a method table is restored */
5358 /****************************************************************************/
5359 VOID ETW::MethodLog::MethodTableRestored(MethodTable *pMethodTable)
5360 {
5361     CONTRACTL {
5362         NOTHROW;
5363         GC_TRIGGERS;
5364     } CONTRACTL_END;
5365     EX_TRY
5366     {
5367         if(IsRuntimeNgenKeywordEnabledAndNotSuppressed()
5368             && 
5369             ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5370                                          TRACE_LEVEL_INFORMATION, 
5371                                          CLR_STARTENUMERATION_KEYWORD))
5372         {
5373             {
5374                 MethodTable::MethodIterator iter(pMethodTable);
5375                 for (; iter.IsValid(); iter.Next())
5376                 {
5377                     MethodDesc *pMD = (MethodDesc *)(iter.GetMethodDesc());
5378                     if(pMD && pMD->IsRestored() && pMD->GetMethodTable_NoLogging() == pMethodTable)
5379                         ETW::MethodLog::SendMethodEvent(pMD, ETW::EnumerationLog::EnumerationStructs::NgenMethodLoad, FALSE);
5380                 }
5381             }
5382         }
5383     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5384 }
5385
5386
5387 /****************************************************************************/
5388 /* This is called by the runtime when a Strong Name Verification Starts */
5389 /****************************************************************************/
5390 VOID ETW::SecurityLog::StrongNameVerificationStart(DWORD dwInFlags, __in LPWSTR strFullyQualifiedAssemblyName)
5391 {
5392     WRAPPER_NO_CONTRACT;
5393 }
5394
5395
5396 /****************************************************************************/
5397 /* This is called by the runtime when a Strong Name Verification Ends */
5398 /****************************************************************************/
5399 VOID ETW::SecurityLog::StrongNameVerificationStop(DWORD dwInFlags,ULONG result, __in LPWSTR strFullyQualifiedAssemblyName)
5400 {
5401     WRAPPER_NO_CONTRACT;
5402 }
5403
5404 /****************************************************************************/
5405 /* This is called by the runtime when field transparency calculations begin */
5406 /****************************************************************************/
5407 void ETW::SecurityLog::FireFieldTransparencyComputationStart(LPCWSTR wszFieldName,
5408                                                              LPCWSTR wszModuleName,
5409                                                              DWORD dwAppDomain)
5410 {
5411     WRAPPER_NO_CONTRACT;
5412     FireEtwFieldTransparencyComputationStart(wszFieldName, wszModuleName, dwAppDomain, GetClrInstanceId());
5413 }
5414
5415 /****************************************************************************/
5416 /* This is called by the runtime when field transparency calculations end   */
5417 /****************************************************************************/
5418 void ETW::SecurityLog::FireFieldTransparencyComputationEnd(LPCWSTR wszFieldName,
5419                                                            LPCWSTR wszModuleName,
5420                                                            DWORD dwAppDomain,
5421                                                            BOOL fIsCritical,
5422                                                            BOOL fIsTreatAsSafe)
5423 {
5424     WRAPPER_NO_CONTRACT;
5425     FireEtwFieldTransparencyComputationEnd(wszFieldName, wszModuleName, dwAppDomain, fIsCritical, fIsTreatAsSafe, GetClrInstanceId());
5426 }
5427
5428 /*****************************************************************************/
5429 /* This is called by the runtime when method transparency calculations begin */
5430 /*****************************************************************************/
5431 void ETW::SecurityLog::FireMethodTransparencyComputationStart(LPCWSTR wszMethodName,
5432                                                               LPCWSTR wszModuleName,
5433                                                               DWORD dwAppDomain)
5434 {
5435     WRAPPER_NO_CONTRACT;
5436     FireEtwMethodTransparencyComputationStart(wszMethodName, wszModuleName, dwAppDomain, GetClrInstanceId());
5437 }
5438
5439 /*****************************************************************************/
5440 /* This is called by the runtime when method transparency calculations end   */
5441 /********************************************(********************************/
5442 void ETW::SecurityLog::FireMethodTransparencyComputationEnd(LPCWSTR wszMethodName,
5443                                                             LPCWSTR wszModuleName,
5444                                                             DWORD dwAppDomain,
5445                                                             BOOL fIsCritical,
5446                                                             BOOL fIsTreatAsSafe)
5447 {
5448     WRAPPER_NO_CONTRACT;
5449     FireEtwMethodTransparencyComputationEnd(wszMethodName, wszModuleName, dwAppDomain, fIsCritical, fIsTreatAsSafe, GetClrInstanceId());
5450 }
5451
5452 /*****************************************************************************/
5453 /* This is called by the runtime when module transparency calculations begin */
5454 /*****************************************************************************/
5455 void ETW::SecurityLog::FireModuleTransparencyComputationStart(LPCWSTR wszModuleName,
5456                                                               DWORD dwAppDomain)
5457 {
5458     WRAPPER_NO_CONTRACT;
5459     FireEtwModuleTransparencyComputationStart(wszModuleName, dwAppDomain, GetClrInstanceId());
5460 }
5461
5462 /****************************************************************************/
5463 /* This is called by the runtime when module transparency calculations end  */
5464 /****************************************************************************/
5465 void ETW::SecurityLog::FireModuleTransparencyComputationEnd(LPCWSTR wszModuleName,
5466                                                             DWORD dwAppDomain,
5467                                                             BOOL fIsAllCritical,
5468                                                             BOOL fIsAllTransparent,
5469                                                             BOOL fIsTreatAsSafe,
5470                                                             BOOL fIsOpportunisticallyCritical,
5471                                                             DWORD dwSecurityRuleSet)
5472 {
5473     WRAPPER_NO_CONTRACT;
5474     FireEtwModuleTransparencyComputationEnd(wszModuleName, dwAppDomain, fIsAllCritical, fIsAllTransparent, fIsTreatAsSafe, fIsOpportunisticallyCritical, dwSecurityRuleSet, GetClrInstanceId());
5475 }
5476
5477 /****************************************************************************/
5478 /* This is called by the runtime when token transparency calculations begin */
5479 /****************************************************************************/
5480 void ETW::SecurityLog::FireTokenTransparencyComputationStart(DWORD dwToken,
5481                                                              LPCWSTR wszModuleName,
5482                                                              DWORD dwAppDomain)
5483 {
5484     WRAPPER_NO_CONTRACT;
5485     FireEtwTokenTransparencyComputationStart(dwToken, wszModuleName, dwAppDomain, GetClrInstanceId());
5486 }
5487
5488 /****************************************************************************/
5489 /* This is called by the runtime when token transparency calculations end   */
5490 /****************************************************************************/
5491 void ETW::SecurityLog::FireTokenTransparencyComputationEnd(DWORD dwToken,
5492                                                            LPCWSTR wszModuleName,
5493                                                            DWORD dwAppDomain,
5494                                                            BOOL fIsCritical,
5495                                                            BOOL fIsTreatAsSafe)
5496 {
5497     WRAPPER_NO_CONTRACT;
5498     FireEtwTokenTransparencyComputationEnd(dwToken, wszModuleName, dwAppDomain, fIsCritical, fIsTreatAsSafe, GetClrInstanceId());
5499 }
5500
5501 /*****************************************************************************/
5502 /* This is called by the runtime when type transparency calculations begin   */
5503 /*****************************************************************************/
5504 void ETW::SecurityLog::FireTypeTransparencyComputationStart(LPCWSTR wszTypeName,
5505                                                             LPCWSTR wszModuleName,
5506                                                             DWORD dwAppDomain)
5507 {
5508     WRAPPER_NO_CONTRACT;
5509     FireEtwTypeTransparencyComputationStart(wszTypeName, wszModuleName, dwAppDomain, GetClrInstanceId());
5510 }
5511
5512 /****************************************************************************/
5513 /* This is called by the runtime when type transparency calculations end    */
5514 /****************************************************************************/
5515 void ETW::SecurityLog::FireTypeTransparencyComputationEnd(LPCWSTR wszTypeName,
5516                                                           LPCWSTR wszModuleName,
5517                                                           DWORD dwAppDomain,
5518                                                           BOOL fIsAllCritical,
5519                                                           BOOL fIsAllTransparent,
5520                                                           BOOL fIsCritical,
5521                                                           BOOL fIsTreatAsSafe)
5522 {
5523     WRAPPER_NO_CONTRACT;
5524     FireEtwTypeTransparencyComputationEnd(wszTypeName, wszModuleName, dwAppDomain, fIsAllCritical, fIsAllTransparent, fIsCritical, fIsTreatAsSafe, GetClrInstanceId());
5525 }
5526
5527 /**********************************************************************************/
5528 /* This is called by the runtime when a module is loaded */
5529 /* liReportedSharedModule will be 0 when this module is reported for the 1st time */
5530 /**********************************************************************************/
5531 VOID ETW::LoaderLog::ModuleLoad(Module *pModule, LONG liReportedSharedModule)
5532 {
5533     CONTRACTL {
5534         NOTHROW;
5535         GC_TRIGGERS;
5536     } CONTRACTL_END;
5537
5538     EX_TRY
5539     {
5540         DWORD enumerationOptions = ETW::EnumerationLog::EnumerationStructs::None;
5541         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5542                                         TRACE_LEVEL_INFORMATION, 
5543                                         KEYWORDZERO))
5544         {
5545             BOOL bTraceFlagLoaderSet = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5546                                                                     TRACE_LEVEL_INFORMATION, 
5547                                                                     CLR_LOADER_KEYWORD);
5548             BOOL bTraceFlagNgenMethodSet = IsRuntimeNgenKeywordEnabledAndNotSuppressed();
5549             BOOL bTraceFlagStartRundownSet = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5550                                                                           TRACE_LEVEL_INFORMATION, 
5551                                                                           CLR_STARTENUMERATION_KEYWORD);
5552             BOOL bTraceFlagPerfTrackSet = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
5553                                                                           TRACE_LEVEL_INFORMATION, 
5554                                                                           CLR_PERFTRACK_KEYWORD);
5555
5556             if(liReportedSharedModule == 0)
5557             {
5558
5559                 if(bTraceFlagLoaderSet)
5560                     enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad;
5561                 if (bTraceFlagPerfTrackSet)
5562                     enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoad;
5563                 if(bTraceFlagNgenMethodSet && bTraceFlagStartRundownSet)
5564                     enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::NgenMethodLoad;
5565
5566                 if(pModule->IsManifest() && bTraceFlagLoaderSet)
5567                     ETW::LoaderLog::SendAssemblyEvent(pModule->GetAssembly(), enumerationOptions);
5568
5569                 if(bTraceFlagLoaderSet || bTraceFlagPerfTrackSet)
5570                     ETW::LoaderLog::SendModuleEvent(pModule, ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad | ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoad);
5571
5572                 ETW::EnumerationLog::EnumerationHelper(pModule, NULL, enumerationOptions);
5573             }
5574
5575             // we want to report domainmodule events whenever they are loaded in any AppDomain
5576             if(bTraceFlagLoaderSet)
5577                 ETW::LoaderLog::SendModuleEvent(pModule, ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad, TRUE);
5578         }
5579
5580         {
5581             BOOL bTraceFlagPerfTrackPrivateSet = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context,
5582                                                                                 TRACE_LEVEL_INFORMATION,
5583                                                                                 CLR_PERFTRACK_PRIVATE_KEYWORD);
5584             if (liReportedSharedModule == 0 && bTraceFlagPerfTrackPrivateSet)
5585             {
5586                 enumerationOptions |= ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoadPrivate;
5587                 ETW::LoaderLog::SendModuleRange(pModule, enumerationOptions);
5588             }
5589         }
5590     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5591 }
5592
5593 /****************************************************************************/
5594 /* This is called by the runtime when the process is being shutdown */
5595 /****************************************************************************/
5596 VOID ETW::EnumerationLog::ProcessShutdown()
5597 {
5598     CONTRACTL {
5599         NOTHROW;
5600         GC_TRIGGERS;
5601     } CONTRACTL_END;
5602
5603     EX_TRY
5604     {
5605         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, KEYWORDZERO))
5606         {
5607             DWORD enumerationOptions = GetEnumerationOptionsFromRuntimeKeywords();
5608
5609             // Send unload events for all remaining domains, including shared domain and
5610             // default domain.
5611             ETW::EnumerationLog::EnumerationHelper(NULL /* module filter */, NULL /* domain filter */, enumerationOptions);
5612         }
5613     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
5614 }
5615
5616 /****************************************************************************/
5617 /****************************************************************************/
5618 /* Begining of helper functions */
5619 /****************************************************************************/
5620 /****************************************************************************/
5621
5622 /****************************************************************************/
5623 /* This routine is used to send a domain load/unload or rundown event                              */
5624 /****************************************************************************/
5625 VOID ETW::LoaderLog::SendDomainEvent(BaseDomain *pBaseDomain, DWORD dwEventOptions, LPCWSTR wszFriendlyName)
5626 {
5627     CONTRACTL {
5628         THROWS;
5629         GC_TRIGGERS;
5630     } CONTRACTL_END;
5631
5632     if(!pBaseDomain)
5633         return;
5634
5635     PCWSTR szDtraceOutput1=W("");
5636     BOOL bIsDefaultDomain = pBaseDomain->IsDefaultDomain();
5637     BOOL bIsAppDomain = pBaseDomain->IsAppDomain();
5638     BOOL bIsExecutable = bIsAppDomain ? !(pBaseDomain->AsAppDomain()->IsPassiveDomain()) : FALSE;
5639     BOOL bIsSharedDomain = pBaseDomain->IsSharedDomain();
5640     UINT32 uSharingPolicy = bIsAppDomain?(pBaseDomain->AsAppDomain()->GetSharePolicy()):0;
5641
5642     ULONGLONG ullDomainId = (ULONGLONG)pBaseDomain;
5643     ULONG ulDomainFlags = ((bIsDefaultDomain ? ETW::LoaderLog::LoaderStructs::DefaultDomain : 0) | 
5644                            (bIsExecutable ? ETW::LoaderLog::LoaderStructs::ExecutableDomain : 0) |
5645                            (bIsSharedDomain ? ETW::LoaderLog::LoaderStructs::SharedDomain : 0) |
5646                            (uSharingPolicy<<28));
5647
5648     LPCWSTR wsEmptyString = W("");
5649     LPCWSTR wsSharedString = W("SharedDomain");
5650
5651     LPWSTR lpswzDomainName = (LPWSTR)wsEmptyString;
5652
5653     if(bIsAppDomain)
5654     {
5655         if(wszFriendlyName)
5656             lpswzDomainName = (PWCHAR)wszFriendlyName;
5657         else
5658             lpswzDomainName = (PWCHAR)pBaseDomain->AsAppDomain()->GetFriendlyName();
5659     }
5660     else
5661         lpswzDomainName = (LPWSTR)wsSharedString;
5662
5663     /* prepare events args for ETW and ETM */
5664     szDtraceOutput1 = (PCWSTR)lpswzDomainName;
5665
5666     if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad)
5667     {
5668         FireEtwAppDomainLoad_V1(ullDomainId, ulDomainFlags, szDtraceOutput1, pBaseDomain->GetId().m_dwId, GetClrInstanceId());
5669     }
5670     else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload)
5671     {
5672         FireEtwAppDomainUnload_V1(ullDomainId, ulDomainFlags, szDtraceOutput1, pBaseDomain->GetId().m_dwId, GetClrInstanceId());
5673     }
5674     else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)
5675     {
5676         FireEtwAppDomainDCStart_V1(ullDomainId, ulDomainFlags, szDtraceOutput1, pBaseDomain->GetId().m_dwId, GetClrInstanceId());
5677     }
5678     else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd)
5679     {
5680         FireEtwAppDomainDCEnd_V1(ullDomainId, ulDomainFlags, szDtraceOutput1, pBaseDomain->GetId().m_dwId, GetClrInstanceId());
5681     }
5682     else
5683     {
5684         _ASSERTE((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad) || 
5685                  (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload) ||
5686                  (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart) ||
5687                  (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd));
5688     }
5689 }
5690
5691 /********************************************************/
5692 /* This routine is used to send thread rundown events when ARM is enabled */
5693 /********************************************************/
5694 VOID ETW::EnumerationLog::SendThreadRundownEvent()
5695 {
5696     CONTRACTL {
5697         THROWS;
5698         GC_TRIGGERS;
5699     } CONTRACTL_END;
5700
5701 #ifndef DACCESS_COMPILE
5702     Thread *pThread = NULL;
5703
5704     // Take the thread store lock while we enumerate threads.
5705     ThreadStoreLockHolder tsl;
5706     while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
5707     {
5708         if (pThread->IsUnstarted() || pThread->IsDead())
5709             continue;
5710
5711         // Send thread rundown provider events and thread created runtime provider
5712         // events (depending on which are enabled)
5713         ThreadLog::FireThreadDC(pThread);
5714         ThreadLog::FireThreadCreated(pThread);
5715     }
5716 #endif // !DACCESS_COMPILE
5717 }
5718
5719 /****************************************************************************/
5720 /* This routine is used to send an assembly load/unload or rundown event ****/
5721 /****************************************************************************/
5722
5723 VOID ETW::LoaderLog::SendAssemblyEvent(Assembly *pAssembly, DWORD dwEventOptions)
5724 {
5725     CONTRACTL {
5726         THROWS;
5727         GC_TRIGGERS;
5728     } CONTRACTL_END;
5729
5730     if(!pAssembly) 
5731         return;
5732
5733     PCWSTR szDtraceOutput1=W("");
5734     BOOL bIsDynamicAssembly = pAssembly->IsDynamic();
5735     BOOL bIsCollectibleAssembly = pAssembly->IsCollectible();
5736     BOOL bIsDomainNeutral = pAssembly->IsDomainNeutral() ;
5737     BOOL bHasNativeImage = pAssembly->GetManifestFile()->HasNativeImage();
5738     BOOL bIsReadyToRun = pAssembly->GetManifestFile()->IsILImageReadyToRun();
5739
5740     ULONGLONG ullAssemblyId = (ULONGLONG)pAssembly;
5741     ULONGLONG ullDomainId = (ULONGLONG)pAssembly->GetDomain();
5742     ULONGLONG ullBindingID = 0;
5743     ULONG ulAssemblyFlags = ((bIsDomainNeutral ? ETW::LoaderLog::LoaderStructs::DomainNeutralAssembly : 0) |
5744                              (bIsDynamicAssembly ? ETW::LoaderLog::LoaderStructs::DynamicAssembly : 0) |
5745                              (bHasNativeImage ? ETW::LoaderLog::LoaderStructs::NativeAssembly : 0) |
5746                              (bIsCollectibleAssembly ? ETW::LoaderLog::LoaderStructs::CollectibleAssembly : 0) |
5747                              (bIsReadyToRun ? ETW::LoaderLog::LoaderStructs::ReadyToRunAssembly : 0));
5748
5749     SString sAssemblyPath;
5750     pAssembly->GetDisplayName(sAssemblyPath);
5751     LPWSTR lpszAssemblyPath = (LPWSTR)sAssemblyPath.GetUnicode();
5752
5753 /* prepare events args for ETW and ETM */
5754     szDtraceOutput1 = (PCWSTR)lpszAssemblyPath;
5755
5756     if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad)
5757     {
5758         FireEtwAssemblyLoad_V1(ullAssemblyId, ullDomainId, ullBindingID, ulAssemblyFlags, szDtraceOutput1, GetClrInstanceId());
5759     }
5760     else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload)
5761     {
5762         FireEtwAssemblyUnload_V1(ullAssemblyId, ullDomainId, ullBindingID, ulAssemblyFlags, szDtraceOutput1, GetClrInstanceId());
5763     }
5764     else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)
5765     {
5766         FireEtwAssemblyDCStart_V1(ullAssemblyId, ullDomainId, ullBindingID, ulAssemblyFlags, szDtraceOutput1, GetClrInstanceId());
5767     }
5768     else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd)
5769     {
5770         FireEtwAssemblyDCEnd_V1(ullAssemblyId, ullDomainId, ullBindingID, ulAssemblyFlags, szDtraceOutput1, GetClrInstanceId());
5771     }
5772     else
5773     {
5774         _ASSERTE((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad) ||
5775                  (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload) ||
5776                  (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart) ||
5777                  (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd));
5778     }
5779 }
5780
5781 ETW_INLINE
5782     ULONG
5783     ETW::LoaderLog::SendModuleRange(
5784     __in Module *pModule,
5785     __in DWORD dwEventOptions)
5786
5787 {
5788     ULONG Result = ERROR_SUCCESS;
5789
5790
5791     // do not fire the ETW event when:
5792     // 1. We did not load the native image
5793     // 2. We do not have IBC data for the native image
5794     if( !pModule || !pModule->HasNativeImage() || !pModule->IsIbcOptimized() )
5795     {
5796         return Result;
5797     }
5798
5799     // get information about the hot sections from the native image that has been loaded
5800     COUNT_T cbSizeOfSectionTable;
5801     CORCOMPILE_VIRTUAL_SECTION_INFO* pVirtualSectionsTable = (CORCOMPILE_VIRTUAL_SECTION_INFO* )pModule->GetNativeImage()->GetVirtualSectionsTable(&cbSizeOfSectionTable);
5802
5803     COUNT_T RangeCount = cbSizeOfSectionTable/sizeof(CORCOMPILE_VIRTUAL_SECTION_INFO);
5804
5805     // if we do not have any hot ranges, we do not fire the ETW event
5806
5807     // Figure out the rest of the event data
5808     UINT16 ClrInstanceId = GetClrInstanceId();
5809     UINT64 ModuleID = (ULONGLONG)(TADDR) pModule;    
5810
5811     for (COUNT_T i = 0; i < RangeCount; ++i)
5812     {
5813         DWORD rangeBegin = pVirtualSectionsTable[i].VirtualAddress;
5814         DWORD rangeSize = pVirtualSectionsTable[i].Size;
5815         DWORD sectionType = pVirtualSectionsTable[i].SectionType;
5816
5817         UINT8 ibcType = VirtualSectionData::IBCType(sectionType);
5818         UINT8 rangeType = VirtualSectionData::RangeType(sectionType);
5819         UINT16 virtualSectionType = VirtualSectionData::VirtualSectionType(sectionType);
5820         BOOL isIBCProfiledColdSection = VirtualSectionData::IsIBCProfiledColdSection(sectionType);
5821         if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoad)
5822         {
5823             if (isIBCProfiledColdSection)
5824                 Result &= FireEtwModuleRangeLoad(ClrInstanceId, ModuleID, rangeBegin, rangeSize, rangeType);
5825         }
5826         else if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCStart)
5827         {
5828             if (isIBCProfiledColdSection)
5829                 Result &= FireEtwModuleRangeDCStart(ClrInstanceId, ModuleID, rangeBegin, rangeSize, rangeType);
5830         }
5831         else if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCEnd)
5832         {
5833             if (isIBCProfiledColdSection)
5834                 Result &= FireEtwModuleRangeDCEnd(ClrInstanceId, ModuleID, rangeBegin, rangeSize, rangeType);
5835         }
5836         // Fire private events if they are requested.
5837         if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoadPrivate)
5838         {
5839             Result &= FireEtwModuleRangeLoadPrivate(ClrInstanceId, ModuleID, rangeBegin, rangeSize, rangeType, ibcType, virtualSectionType);
5840         }
5841     }
5842     return Result;
5843 }
5844
5845 //---------------------------------------------------------------------------------------
5846 //
5847 // Helper that takes a module, and returns the managed and native PDB information
5848 // corresponding to that module. Used by the routine that fires the module load / unload
5849 // events.
5850 //
5851 // Arguments:
5852 //      * pModule - Module to examine
5853 //      * pCvInfoIL - [out] CV_INFO_PDB70 corresponding to managed PDB for this module
5854 //          (the last debug directory entry in the PE File), if it exists. If it doesn't
5855 //          exist, this is zeroed out.
5856 //      * pCvInfoNative - [out] CV_INFO_PDB70 corresponding to native NGEN PDB for this
5857 //          module (the next-to-last debug directory entry in the PE File), if it exists.
5858 //          If it doesn't exist, this is zeroed out.
5859 //
5860 // Notes:
5861 //     * This method only understands the CV_INFO_PDB70 / RSDS format. If the format
5862 //         changes, this function will act as if there are no debug directory entries.
5863 //         Module load / unload events will still be fired, but all PDB info will be
5864 //         zeroed out.
5865 //     * The raw data in the PE file's debug directory entries are assumed to be
5866 //         untrusted, and reported sizes of buffers are verified against their data.
5867 //
5868
5869 static void GetCodeViewInfo(Module * pModule, CV_INFO_PDB70 * pCvInfoIL, CV_INFO_PDB70 * pCvInfoNative)
5870 {
5871     LIMITED_METHOD_CONTRACT;
5872
5873     _ASSERTE (pModule != NULL);
5874     _ASSERTE (pCvInfoIL != NULL);
5875     _ASSERTE (pCvInfoNative != NULL);
5876
5877     ZeroMemory(pCvInfoIL, sizeof(*pCvInfoIL));
5878     ZeroMemory(pCvInfoNative, sizeof(*pCvInfoNative));
5879
5880     PTR_PEFile pPEFile = pModule->GetFile();
5881     _ASSERTE(pPEFile != NULL);
5882
5883     PTR_PEImageLayout pLayout = NULL;
5884     if (pPEFile->HasNativeImage())
5885     {
5886         pLayout = pPEFile->GetLoadedNative();
5887     }
5888     else if (pPEFile->HasOpenedILimage())
5889     {
5890         pLayout = pPEFile->GetLoadedIL();
5891     }
5892
5893     if (pLayout == NULL)
5894     {
5895         // This can happen for reflection-loaded modules
5896         return;
5897     }
5898
5899     if (!pLayout->HasNTHeaders())
5900     {
5901         // Without NT headers, we'll have a tough time finding the debug directory
5902         // entries. This can happen for nlp files.
5903         return;
5904     }
5905
5906     if (!pLayout->HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG))
5907         return;
5908
5909     COUNT_T cbDebugEntries;
5910     IMAGE_DEBUG_DIRECTORY * rgDebugEntries = 
5911         (IMAGE_DEBUG_DIRECTORY *) pLayout->GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &cbDebugEntries);
5912
5913     if (cbDebugEntries < sizeof(IMAGE_DEBUG_DIRECTORY)) 
5914         return;
5915
5916     // Since rgDebugEntries is an array of IMAGE_DEBUG_DIRECTORYs, cbDebugEntries
5917     // should be a multiple of sizeof(IMAGE_DEBUG_DIRECTORY).
5918     if (cbDebugEntries % sizeof(IMAGE_DEBUG_DIRECTORY) != 0)
5919         return;
5920
5921     // Temporary storage for a CV_INFO_PDB70 and its size (which could be less than
5922     // sizeof(CV_INFO_PDB70); see below).
5923     struct PdbInfo
5924     {
5925         CV_INFO_PDB70 *     m_pPdb70;
5926         ULONG               m_cbPdb70;
5927     };
5928
5929     // Iterate through all debug directory entries.  The very last one will be the
5930     // managed PDB entry.  The next to last one (if it exists) will be the (native) NGEN
5931     // PDB entry.  Treat raw bytes we read as untrusted.
5932     PdbInfo pdbInfoLast = {0};
5933     PdbInfo pdbInfoNextToLast = {0};
5934     int cEntries = cbDebugEntries / sizeof(IMAGE_DEBUG_DIRECTORY);
5935     for (int i = 0; i < cEntries; i++)
5936     {
5937         if (rgDebugEntries[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW)
5938             continue;
5939
5940         // Get raw data pointed to by this IMAGE_DEBUG_DIRECTORY
5941
5942         // Some compilers set PointerToRawData but not AddressOfRawData as they put the
5943         // data at the end of the file in an unmapped part of the file
5944         RVA rvaOfRawData = (rgDebugEntries[i].AddressOfRawData != NULL) ? 
5945             rgDebugEntries[i].AddressOfRawData : 
5946             pLayout->OffsetToRva(rgDebugEntries[i].PointerToRawData);
5947
5948         ULONG cbDebugData = rgDebugEntries[i].SizeOfData;
5949         if (cbDebugData < (offsetof(CV_INFO_PDB70, magic) + sizeof(((CV_INFO_PDB70*)0)->magic)))
5950         {
5951             // raw data too small to contain magic number at expected spot, so its format
5952             // is not recognizeable. Skip
5953             continue;
5954         }
5955
5956         if (!pLayout->CheckRva(rvaOfRawData, cbDebugData))
5957         {
5958             // Memory claimed to belong to the raw data does not fit.
5959             // IMAGE_DEBUG_DIRECTORY is outright corrupt. Do not include PDB info in
5960             // event at all.
5961             return;
5962         }
5963
5964         // Verify the magic number is as expected
5965         CV_INFO_PDB70 * pPdb70 = (CV_INFO_PDB70 *) pLayout->GetRvaData(rvaOfRawData);
5966         if (pPdb70->magic != CV_SIGNATURE_RSDS)
5967         {
5968             // Unrecognized magic number.  Skip
5969             continue;
5970         }
5971
5972         // From this point forward, the format should adhere to the expected layout of
5973         // CV_INFO_PDB70. If we find otherwise, then assume the IMAGE_DEBUG_DIRECTORY is
5974         // outright corrupt, and do not include PDB info in event at all. The caller will
5975         // still fire the module event, but have zeroed-out / empty PDB fields.
5976
5977         // Verify sane size of raw data
5978         if (cbDebugData > sizeof(CV_INFO_PDB70))
5979             return;
5980
5981         // cbDebugData actually can be < sizeof(CV_INFO_PDB70), since the "path" field
5982         // can be truncated to its actual data length (i.e., fewer than MAX_LONGPATH chars
5983         // may be present in the PE file). In some cases, though, cbDebugData will
5984         // include all MAX_LONGPATH chars even though path gets null-terminated well before
5985         // the MAX_LONGPATH limit.
5986         
5987         // Gotta have at least one byte of the path
5988         if (cbDebugData < offsetof(CV_INFO_PDB70, path) + sizeof(char))
5989             return;
5990         
5991         // How much space is available for the path?
5992         size_t cchPathMaxIncludingNullTerminator = (cbDebugData - offsetof(CV_INFO_PDB70, path)) / sizeof(char);
5993         _ASSERTE(cchPathMaxIncludingNullTerminator >= 1);   // Guaranteed above
5994
5995         // Verify path string fits inside the declared size
5996         size_t cchPathActualExcludingNullTerminator = strnlen(pPdb70->path, cchPathMaxIncludingNullTerminator);
5997         if (cchPathActualExcludingNullTerminator == cchPathMaxIncludingNullTerminator)
5998         {
5999             // This is how strnlen indicates failure--it couldn't find the null
6000             // terminator within the buffer size specified
6001             return;
6002         }
6003
6004         // Looks valid.  Remember it.
6005         pdbInfoNextToLast = pdbInfoLast;
6006         pdbInfoLast.m_pPdb70 = pPdb70;
6007         pdbInfoLast.m_cbPdb70 = cbDebugData;
6008     }
6009
6010     // Return whatever we found
6011     
6012     if (pdbInfoLast.m_pPdb70 != NULL)
6013     {
6014         // The last guy is the IL (managed) PDB info
6015         _ASSERTE(pdbInfoLast.m_cbPdb70 <= sizeof(*pCvInfoIL));      // Guaranteed by checks above
6016         memcpy(pCvInfoIL, pdbInfoLast.m_pPdb70, pdbInfoLast.m_cbPdb70);
6017     }
6018     
6019     if (pdbInfoNextToLast.m_pPdb70 != NULL)
6020     {
6021         // The next-to-last guy is the NGEN (native) PDB info
6022         _ASSERTE(pdbInfoNextToLast.m_cbPdb70 <= sizeof(*pCvInfoNative));      // Guaranteed by checks above
6023         memcpy(pCvInfoNative, pdbInfoNextToLast.m_pPdb70, pdbInfoNextToLast.m_cbPdb70);
6024     }
6025 }
6026
6027
6028 //---------------------------------------------------------------------------------------
6029 //
6030 // send a module load/unload or rundown event and domainmodule load and rundown event
6031 //
6032 // Arguments:
6033 //      * pModule - Module loading or unloading
6034 //      * dwEventOptions - Bitmask of which events to fire
6035 //      * bFireDomainModuleEvents - nonzero if we are to fire DomainModule events; zero
6036 //          if we are to fire Module events
6037 //
6038 VOID ETW::LoaderLog::SendModuleEvent(Module *pModule, DWORD dwEventOptions, BOOL bFireDomainModuleEvents)
6039 {
6040     CONTRACTL {
6041         THROWS;
6042         GC_TRIGGERS;
6043     } CONTRACTL_END;
6044
6045     if(!pModule) 
6046         return;
6047
6048     PCWSTR szDtraceOutput1=W(""),szDtraceOutput2=W("");
6049     BOOL bIsDynamicAssembly = pModule->GetAssembly()->IsDynamic();
6050     BOOL bHasNativeImage = FALSE;
6051 #ifdef FEATURE_PREJIT
6052     bHasNativeImage = pModule->HasNativeImage();
6053 #endif // FEATURE_PREJIT
6054     BOOL bIsManifestModule = pModule->IsManifest();
6055     ULONGLONG ullAppDomainId = 0; // This is used only with DomainModule events
6056     ULONGLONG ullModuleId = (ULONGLONG)(TADDR) pModule;
6057     ULONGLONG ullAssemblyId = (ULONGLONG)pModule->GetAssembly();
6058     BOOL bIsDomainNeutral = pModule->GetAssembly()->IsDomainNeutral();
6059     BOOL bIsIbcOptimized = FALSE;
6060     if(bHasNativeImage)
6061     {
6062         bIsIbcOptimized = pModule->IsIbcOptimized();
6063     }
6064     BOOL bIsReadyToRun = pModule->IsReadyToRun();
6065     ULONG ulReservedFlags = 0;
6066     ULONG ulFlags = ((bIsDomainNeutral ? ETW::LoaderLog::LoaderStructs::DomainNeutralModule : 0) |
6067                      (bHasNativeImage ? ETW::LoaderLog::LoaderStructs::NativeModule : 0) |
6068                      (bIsDynamicAssembly ? ETW::LoaderLog::LoaderStructs::DynamicModule : 0) |
6069                      (bIsManifestModule ? ETW::LoaderLog::LoaderStructs::ManifestModule : 0) |
6070                      (bIsIbcOptimized ? ETW::LoaderLog::LoaderStructs::IbcOptimized : 0) |
6071                      (bIsReadyToRun ? ETW::LoaderLog::LoaderStructs::ReadyToRunModule : 0));
6072
6073     // Grab PDB path, guid, and age for managed PDB and native (NGEN) PDB when
6074     // available.  Any failures are not fatal.  The corresponding PDB info will remain
6075     // zeroed out, and that's what we'll include in the event.
6076     CV_INFO_PDB70 cvInfoIL = {0};
6077     CV_INFO_PDB70 cvInfoNative = {0};
6078     GetCodeViewInfo(pModule, &cvInfoIL, &cvInfoNative);
6079
6080     PWCHAR ModuleILPath=(PWCHAR)W(""), ModuleNativePath=(PWCHAR)W("");
6081
6082     if(bFireDomainModuleEvents)
6083     {
6084         if(pModule->GetDomain()->IsSharedDomain()) // for shared domains, we do not fire domainmodule event
6085             return;
6086         ullAppDomainId = (ULONGLONG)pModule->FindDomainAssembly(pModule->GetDomain()->AsAppDomain())->GetAppDomain();
6087     }
6088
6089     LPCWSTR pEmptyString = W("");
6090     SString moduleName = W("");
6091
6092     if(!bIsDynamicAssembly)
6093     {
6094         ModuleILPath = (PWCHAR)pModule->GetAssembly()->GetManifestFile()->GetILimage()->GetPath().GetUnicode();
6095         ModuleNativePath = (PWCHAR)pEmptyString;
6096
6097 #ifdef FEATURE_PREJIT
6098         if(bHasNativeImage)
6099             ModuleNativePath = (PWCHAR)pModule->GetNativeImage()->GetPath().GetUnicode();
6100 #endif // FEATURE_PREJIT
6101     }
6102     
6103     // if we do not have a module path yet, we put the module name
6104     if(bIsDynamicAssembly || ModuleILPath==NULL || wcslen(ModuleILPath) <= 2)
6105     {
6106         moduleName.SetUTF8(pModule->GetSimpleName());
6107         ModuleILPath = (PWCHAR)moduleName.GetUnicode();
6108         ModuleNativePath = (PWCHAR)pEmptyString;
6109     }
6110
6111     /* prepare events args for ETW and ETM */
6112     szDtraceOutput1 = (PCWSTR)ModuleILPath;
6113     szDtraceOutput2 = (PCWSTR)ModuleNativePath;
6114
6115     // Convert PDB paths to UNICODE
6116     StackSString managedPdbPath(SString::Utf8, cvInfoIL.path);
6117     StackSString nativePdbPath(SString::Utf8, cvInfoNative.path);
6118
6119     if(bFireDomainModuleEvents)
6120     {
6121         if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad)
6122         {
6123             FireEtwDomainModuleLoad_V1(ullModuleId, ullAssemblyId, ullAppDomainId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, GetClrInstanceId());
6124         }
6125         else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)
6126         {
6127             FireEtwDomainModuleDCStart_V1(ullModuleId, ullAssemblyId, ullAppDomainId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, GetClrInstanceId());
6128         }
6129         else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd)
6130         {
6131             FireEtwDomainModuleDCEnd_V1(ullModuleId, ullAssemblyId, ullAppDomainId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, GetClrInstanceId());
6132         }
6133         else
6134         {
6135             _ASSERTE((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad) || 
6136                      (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart) || 
6137                      (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd));
6138         }
6139     }
6140     else
6141     {
6142         if((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad) || (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoad))
6143         {
6144             FireEtwModuleLoad_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, GetClrInstanceId(), &cvInfoIL.signature, cvInfoIL.age, managedPdbPath, &cvInfoNative.signature, cvInfoNative.age, nativePdbPath);
6145         }
6146         else if(dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload)
6147         {
6148             FireEtwModuleUnload_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, GetClrInstanceId(), &cvInfoIL.signature, cvInfoIL.age, managedPdbPath, &cvInfoNative.signature, cvInfoNative.age, nativePdbPath);
6149         }
6150         else if((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart) || (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCStart))
6151         {
6152             FireEtwModuleDCStart_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, GetClrInstanceId(), &cvInfoIL.signature, cvInfoIL.age, managedPdbPath, &cvInfoNative.signature, cvInfoNative.age, nativePdbPath);
6153         }
6154         else if((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) || (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCEnd))
6155         {
6156             FireEtwModuleDCEnd_V1_or_V2(ullModuleId, ullAssemblyId, ulFlags, ulReservedFlags, szDtraceOutput1, szDtraceOutput2, GetClrInstanceId(), &cvInfoIL.signature, cvInfoIL.age, managedPdbPath, &cvInfoNative.signature, cvInfoNative.age, nativePdbPath);
6157         }
6158         else
6159         {
6160             _ASSERTE((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad) || 
6161                      (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload) || 
6162                      (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart) || 
6163                      (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) ||
6164                      (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeEnabledAny));
6165
6166         }
6167
6168         if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeEnabledAny)
6169         {
6170             // Fire ModuleRangeLoad, ModuleRangeDCStart, ModuleRangeDCEnd or ModuleRangeLoadPrivate event for this Module
6171             SendModuleRange(pModule, dwEventOptions);
6172         }
6173     }
6174 }
6175
6176 /*****************************************************************/
6177 /* This routine is used to send an ETW event just before a method starts jitting*/
6178 /*****************************************************************/
6179 VOID ETW::MethodLog::SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature)
6180 {
6181     CONTRACTL {
6182         THROWS;
6183         GC_TRIGGERS;
6184     } CONTRACTL_END;
6185
6186     Module *pModule = NULL;
6187     Module *pLoaderModule = NULL; // This must not be used except for getting the ModuleID
6188
6189     ULONGLONG ullMethodIdentifier=0;
6190     ULONGLONG ullModuleID=0;
6191     ULONG ulMethodToken=0;
6192     ULONG ulMethodILSize=0;
6193     PCWSTR szDtraceOutput1=W(""),szDtraceOutput2=W(""),szDtraceOutput3=W("");
6194
6195     if(pMethodDesc) {
6196         pModule = pMethodDesc->GetModule_NoLogging();
6197
6198         if(!pMethodDesc->IsRestored()) {
6199                 return;
6200         }
6201
6202         bool bIsDynamicMethod = pMethodDesc->IsDynamicMethod();
6203         BOOL bIsGenericMethod = FALSE;
6204         if(pMethodDesc->GetMethodTable_NoLogging())
6205             bIsGenericMethod = pMethodDesc->HasClassOrMethodInstantiation_NoLogging();
6206
6207         ullModuleID = (ULONGLONG)(TADDR) pModule;
6208         ullMethodIdentifier = (ULONGLONG)pMethodDesc;
6209
6210         // Use MethodDesc if Dynamic or Generic methods
6211         if( bIsDynamicMethod || bIsGenericMethod)
6212         {
6213             if(bIsGenericMethod)
6214                 ulMethodToken = (ULONG)pMethodDesc->GetMemberDef_NoLogging();
6215             if(bIsDynamicMethod) // if its a generic and a dynamic method, we would set the methodtoken to 0
6216                 ulMethodToken = (ULONG)0;
6217         }
6218         else
6219             ulMethodToken = (ULONG)pMethodDesc->GetMemberDef_NoLogging();
6220
6221         if(pMethodDesc->IsIL())
6222         {
6223             COR_ILMETHOD_DECODER::DecoderStatus decoderstatus = COR_ILMETHOD_DECODER::FORMAT_ERROR;
6224             COR_ILMETHOD_DECODER ILHeader(pMethodDesc->GetILHeader(), pMethodDesc->GetMDImport(), &decoderstatus);
6225             ulMethodILSize = (ULONG)ILHeader.GetCodeSize();
6226         }
6227
6228         SString tNamespace, tMethodName, tMethodSignature;
6229         if(!namespaceOrClassName|| !methodName|| !methodSignature || (methodName->IsEmpty() && namespaceOrClassName->IsEmpty() && methodSignature->IsEmpty()))
6230         {
6231             pMethodDesc->GetMethodInfo(tNamespace, tMethodName, tMethodSignature);
6232             namespaceOrClassName = &tNamespace; 
6233             methodName = &tMethodName;
6234             methodSignature = &tMethodSignature;
6235         }
6236
6237         // fire method information
6238         /* prepare events args for ETW and ETM */
6239         szDtraceOutput1 = (PCWSTR)namespaceOrClassName->GetUnicode();
6240         szDtraceOutput2 = (PCWSTR)methodName->GetUnicode();
6241         szDtraceOutput3 = (PCWSTR)methodSignature->GetUnicode();
6242
6243         FireEtwMethodJittingStarted_V1(ullMethodIdentifier, 
6244                                        ullModuleID, 
6245                                        ulMethodToken, 
6246                                        ulMethodILSize, 
6247                                        szDtraceOutput1,
6248                                        szDtraceOutput2,
6249                                        szDtraceOutput3,
6250                                        GetClrInstanceId());
6251     }
6252 }
6253
6254 /****************************************************************************/
6255 /* This routine is used to send a method load/unload or rundown event                              */
6256 /****************************************************************************/
6257 VOID ETW::MethodLog::SendMethodEvent(MethodDesc *pMethodDesc, DWORD dwEventOptions, BOOL bIsJit, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, SIZE_T pCode, ReJITID rejitID, BOOL bProfilerRejectedPrecompiledCode, BOOL bReadyToRunRejectedPrecompiledCode)
6258 {
6259     CONTRACTL {
6260         THROWS;
6261         GC_NOTRIGGER;
6262         SO_NOT_MAINLINE;
6263     } CONTRACTL_END;
6264
6265     Module *pModule = NULL;
6266     Module *pLoaderModule = NULL; // This must not be used except for getting the ModuleID
6267     ULONGLONG ullMethodStartAddress=0, ullColdMethodStartAddress=0, ullModuleID=0, ullMethodIdentifier=0;
6268     ULONG ulMethodSize=0, ulColdMethodSize=0, ulMethodToken=0, ulMethodFlags=0, ulColdMethodFlags=0;
6269     PWCHAR pMethodName=NULL, pNamespaceName=NULL, pMethodSignature=NULL;
6270     BOOL bHasNativeImage = FALSE, bShowVerboseOutput = FALSE, bIsDynamicMethod = FALSE, bHasSharedGenericCode = FALSE, bIsGenericMethod = FALSE;
6271     PCWSTR szDtraceOutput1=W(""),szDtraceOutput2=W(""),szDtraceOutput3=W("");
6272     
6273     BOOL bIsRundownProvider = ((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodDCStart) ||
6274                                (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodDCEnd) ||
6275                                (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCStart) ||
6276                                (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCEnd));
6277
6278     BOOL bIsRuntimeProvider = ((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoad) ||
6279                                (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnload) ||
6280                                (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodLoad) ||
6281                                (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodUnload));
6282
6283     if (pMethodDesc == NULL)
6284         return;
6285
6286     if(!pMethodDesc->IsRestored()) 
6287     {
6288         // Forcibly restoring ngen methods can cause all sorts of deadlocks and contract violations
6289         // These events are therefore put under the private provider
6290         if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, 
6291                                         TRACE_LEVEL_INFORMATION, 
6292                                         CLR_PRIVATENGENFORCERESTORE_KEYWORD))
6293         {
6294             PERMANENT_CONTRACT_VIOLATION(GCViolation, ReasonNonShippingCode);
6295             pMethodDesc->CheckRestore();
6296         }
6297         else
6298         {
6299             return;
6300         }
6301     }
6302
6303
6304     if(bIsRundownProvider)
6305     {
6306         bShowVerboseOutput = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context, 
6307             TRACE_LEVEL_VERBOSE, 
6308             KEYWORDZERO);        
6309     }
6310     else if(bIsRuntimeProvider)
6311     {
6312         bShowVerboseOutput = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
6313             TRACE_LEVEL_VERBOSE, 
6314             KEYWORDZERO);
6315     }
6316
6317     pModule = pMethodDesc->GetModule_NoLogging();
6318 #ifdef FEATURE_PREJIT
6319     bHasNativeImage = pModule->HasNativeImage();
6320 #endif // FEATURE_PREJIT
6321     bIsDynamicMethod = (BOOL)pMethodDesc->IsDynamicMethod();
6322     bHasSharedGenericCode = pMethodDesc->IsSharedByGenericInstantiations();
6323
6324     if(pMethodDesc->GetMethodTable_NoLogging())
6325         bIsGenericMethod = pMethodDesc->HasClassOrMethodInstantiation_NoLogging();
6326
6327     ulMethodFlags = ((ulMethodFlags |
6328         (bHasSharedGenericCode ? ETW::MethodLog::MethodStructs::SharedGenericCode : 0) |
6329         (bIsGenericMethod ? ETW::MethodLog::MethodStructs::GenericMethod : 0) |
6330         (bIsDynamicMethod ? ETW::MethodLog::MethodStructs::DynamicMethod : 0) |
6331         (bIsJit ? ETW::MethodLog::MethodStructs::JittedMethod : 0) |
6332         (bProfilerRejectedPrecompiledCode ? ETW::MethodLog::MethodStructs::ProfilerRejectedPrecompiledCode : 0) |
6333         (bReadyToRunRejectedPrecompiledCode ? ETW::MethodLog::MethodStructs::ReadyToRunRejectedPrecompiledCode : 0)));
6334
6335     // Intentionally set the extent flags (cold vs. hot) only after all the other common
6336     // flags (above) have been set.
6337     ulColdMethodFlags = ulMethodFlags | ETW::MethodLog::MethodStructs::ColdSection; // Method Extent (bits 28, 29, 30, 31)
6338     ulMethodFlags = ulMethodFlags | ETW::MethodLog::MethodStructs::HotSection;         // Method Extent (bits 28, 29, 30, 31)
6339
6340     // MethodDesc ==> Code Address ==>JitMananger 
6341     TADDR start = pCode ? pCode : PCODEToPINSTR(pMethodDesc->GetNativeCode());
6342     if(start == 0) {
6343         // this method hasn't been jitted
6344         return;
6345     }
6346
6347     // EECodeInfo is technically initialized by a "PCODE", but it can also be initialized
6348     // by a TADDR (i.e., w/out thumb bit set on ARM)
6349     EECodeInfo codeInfo(start);
6350
6351     // MethodToken ==> MethodRegionInfo
6352     IJitManager::MethodRegionInfo methodRegionInfo;
6353     codeInfo.GetMethodRegionInfo(&methodRegionInfo);
6354
6355     ullMethodStartAddress = (ULONGLONG)methodRegionInfo.hotStartAddress;
6356     ulMethodSize = (ULONG)methodRegionInfo.hotSize;
6357
6358     ullModuleID = (ULONGLONG)(TADDR) pModule;
6359     ullMethodIdentifier = (ULONGLONG)pMethodDesc;
6360
6361     // Use MethodDesc if Dynamic or Generic methods
6362     if( bIsDynamicMethod || bIsGenericMethod)
6363     {
6364         bShowVerboseOutput = TRUE;
6365         if(bIsGenericMethod)
6366             ulMethodToken = (ULONG)pMethodDesc->GetMemberDef_NoLogging();
6367         if(bIsDynamicMethod) // if its a generic and a dynamic method, we would set the methodtoken to 0
6368             ulMethodToken = (ULONG)0;
6369     }
6370     else
6371         ulMethodToken = (ULONG)pMethodDesc->GetMemberDef_NoLogging();
6372
6373     if(bHasNativeImage)
6374     {
6375         ullColdMethodStartAddress = (ULONGLONG)methodRegionInfo.coldStartAddress;
6376         ulColdMethodSize = (ULONG)methodRegionInfo.coldSize; // methodRegionInfo.coldSize is size_t and info.MethodLoadInfo.MethodSize is 32 bit; will give incorrect values on a 64-bit machine
6377     }
6378
6379     SString tNamespace, tMethodName, tMethodSignature;
6380
6381     // if verbose method load info needed, only then 
6382     // find method name and signature and fire verbose method load info
6383     if(bShowVerboseOutput) 
6384     {
6385         if(!namespaceOrClassName|| !methodName|| !methodSignature || (methodName->IsEmpty() && namespaceOrClassName->IsEmpty() && methodSignature->IsEmpty()))
6386         {
6387             pMethodDesc->GetMethodInfo(tNamespace, tMethodName, tMethodSignature);
6388             namespaceOrClassName = &tNamespace; 
6389             methodName = &tMethodName;
6390             methodSignature = &tMethodSignature;
6391         }
6392         pNamespaceName = (PWCHAR)namespaceOrClassName->GetUnicode();
6393         pMethodName = (PWCHAR)methodName->GetUnicode();
6394         pMethodSignature = (PWCHAR)methodSignature->GetUnicode();
6395     }
6396
6397     BOOL bFireEventForColdSection = (bHasNativeImage && ullColdMethodStartAddress && ulColdMethodSize);
6398
6399     /* prepare events args for ETW and ETM */
6400     szDtraceOutput1 = (PCWSTR)pNamespaceName;
6401     szDtraceOutput2 = (PCWSTR)pMethodName;
6402     szDtraceOutput3 = (PCWSTR)pMethodSignature;
6403
6404     if((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoad) ||
6405         (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodLoad))
6406     {
6407         if(bShowVerboseOutput)
6408         {
6409             FireEtwMethodLoadVerbose_V1_or_V2(ullMethodIdentifier, 
6410                 ullModuleID, 
6411                 ullMethodStartAddress, 
6412                 ulMethodSize, 
6413                 ulMethodToken, 
6414                 ulMethodFlags, 
6415                 szDtraceOutput1, 
6416                 szDtraceOutput2, 
6417                 szDtraceOutput3, 
6418                 GetClrInstanceId(),
6419                 rejitID);
6420         }
6421         else
6422         {
6423             FireEtwMethodLoad_V1_or_V2(ullMethodIdentifier, 
6424                 ullModuleID, 
6425                 ullMethodStartAddress, 
6426                 ulMethodSize, 
6427                 ulMethodToken, 
6428                 ulMethodFlags, 
6429                 GetClrInstanceId(),
6430                 rejitID);
6431         }
6432         if(bFireEventForColdSection)
6433         {
6434             if(bShowVerboseOutput)
6435             {
6436                 FireEtwMethodLoadVerbose_V1_or_V2(ullMethodIdentifier, 
6437                     ullModuleID, 
6438                     ullColdMethodStartAddress, 
6439                     ulColdMethodSize, 
6440                     ulMethodToken, 
6441                     ulColdMethodFlags, 
6442                     szDtraceOutput1, 
6443                     szDtraceOutput2, 
6444                     szDtraceOutput3, 
6445                     GetClrInstanceId(),
6446                     rejitID);
6447             }
6448             else
6449             {
6450                 FireEtwMethodLoad_V1_or_V2(ullMethodIdentifier, 
6451                     ullModuleID, 
6452                     ullColdMethodStartAddress, 
6453                     ulColdMethodSize, 
6454                     ulMethodToken, 
6455                     ulColdMethodFlags, 
6456                     GetClrInstanceId(),
6457                     rejitID);
6458             }
6459         }
6460     }
6461     else if((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnload) ||
6462         (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodUnload))
6463     {
6464         if(bShowVerboseOutput)
6465         {
6466             FireEtwMethodUnloadVerbose_V1_or_V2(ullMethodIdentifier, 
6467                 ullModuleID, 
6468                 ullMethodStartAddress, 
6469                 ulMethodSize, 
6470                 ulMethodToken, 
6471                 ulMethodFlags, 
6472                 szDtraceOutput1, 
6473                 szDtraceOutput2, 
6474                 szDtraceOutput3, 
6475                 GetClrInstanceId(),
6476                 rejitID);
6477         }
6478         else
6479         {
6480             FireEtwMethodUnload_V1_or_V2(ullMethodIdentifier, 
6481                 ullModuleID, 
6482                 ullMethodStartAddress, 
6483                 ulMethodSize, 
6484                 ulMethodToken, 
6485                 ulMethodFlags, 
6486                 GetClrInstanceId(),
6487                 rejitID);
6488         }
6489         if(bFireEventForColdSection)
6490         {
6491             if(bShowVerboseOutput)
6492             {
6493                 FireEtwMethodUnloadVerbose_V1_or_V2(ullMethodIdentifier, 
6494                     ullModuleID, 
6495                     ullColdMethodStartAddress, 
6496                     ulColdMethodSize, 
6497                     ulMethodToken, 
6498                     ulColdMethodFlags, 
6499                     szDtraceOutput1, 
6500                     szDtraceOutput2, 
6501                     szDtraceOutput3, 
6502                     GetClrInstanceId(),
6503                     rejitID);
6504             }
6505             else
6506             {
6507                 FireEtwMethodUnload_V1_or_V2(ullMethodIdentifier, 
6508                     ullModuleID, 
6509                     ullColdMethodStartAddress, 
6510                     ulColdMethodSize, 
6511                     ulMethodToken, 
6512                     ulColdMethodFlags, 
6513                     GetClrInstanceId(),
6514                     rejitID);
6515             }
6516         }
6517     }
6518     else if((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodDCStart) ||
6519         (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCStart))
6520     {
6521         if(bShowVerboseOutput)
6522         {
6523             FireEtwMethodDCStartVerbose_V1_or_V2(ullMethodIdentifier, 
6524                 ullModuleID, 
6525                 ullMethodStartAddress, 
6526                 ulMethodSize, 
6527                 ulMethodToken, 
6528                 ulMethodFlags, 
6529                 szDtraceOutput1, 
6530                 szDtraceOutput2, 
6531                 szDtraceOutput3, 
6532                 GetClrInstanceId(),
6533                 rejitID);
6534         }
6535         else
6536         {
6537             FireEtwMethodDCStart_V1_or_V2(ullMethodIdentifier, 
6538                 ullModuleID, 
6539                 ullMethodStartAddress, 
6540                 ulMethodSize, 
6541                 ulMethodToken, 
6542                 ulMethodFlags, 
6543                 GetClrInstanceId(),
6544                 rejitID);
6545         }
6546         if(bFireEventForColdSection)
6547         {
6548             if(bShowVerboseOutput)
6549             {
6550                 FireEtwMethodDCStartVerbose_V1_or_V2(ullMethodIdentifier, 
6551                     ullModuleID, 
6552                     ullColdMethodStartAddress, 
6553                     ulColdMethodSize, 
6554                     ulMethodToken, 
6555                     ulColdMethodFlags, 
6556                     szDtraceOutput1, 
6557                     szDtraceOutput2, 
6558                     szDtraceOutput3, 
6559                     GetClrInstanceId(),
6560                     rejitID);
6561             }
6562             else
6563             {
6564                 FireEtwMethodDCStart_V1_or_V2(ullMethodIdentifier, 
6565                     ullModuleID, 
6566                     ullColdMethodStartAddress, 
6567                     ulColdMethodSize, 
6568                     ulMethodToken, 
6569                     ulColdMethodFlags, 
6570                     GetClrInstanceId(),
6571                     rejitID);
6572             }
6573         }
6574     }
6575     else if((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodDCEnd) ||
6576         (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCEnd))
6577     {
6578         if(bShowVerboseOutput)
6579         {
6580             FireEtwMethodDCEndVerbose_V1_or_V2(ullMethodIdentifier, 
6581                 ullModuleID, 
6582                 ullMethodStartAddress, 
6583                 ulMethodSize, 
6584                 ulMethodToken, 
6585                 ulMethodFlags, 
6586                 szDtraceOutput1, 
6587                 szDtraceOutput2, 
6588                 szDtraceOutput3, 
6589                 GetClrInstanceId(),
6590                 rejitID);
6591         }
6592         else
6593         {
6594             FireEtwMethodDCEnd_V1_or_V2(ullMethodIdentifier, 
6595                 ullModuleID, 
6596                 ullMethodStartAddress, 
6597                 ulMethodSize, 
6598                 ulMethodToken, 
6599                 ulMethodFlags, 
6600                 GetClrInstanceId(),
6601                 rejitID);
6602         }
6603         if(bFireEventForColdSection)
6604         {
6605             if(bShowVerboseOutput)
6606             {
6607                 FireEtwMethodDCEndVerbose_V1_or_V2(ullMethodIdentifier, 
6608                     ullModuleID, 
6609                     ullColdMethodStartAddress, 
6610                     ulColdMethodSize, 
6611                     ulMethodToken, 
6612                     ulColdMethodFlags, 
6613                     szDtraceOutput1, 
6614                     szDtraceOutput2, 
6615                     szDtraceOutput3, 
6616                     GetClrInstanceId(),
6617                     rejitID);
6618             }
6619             else
6620             {
6621                 FireEtwMethodDCEnd_V1_or_V2(ullMethodIdentifier, 
6622                     ullModuleID, 
6623                     ullColdMethodStartAddress, 
6624                     ulColdMethodSize, 
6625                     ulMethodToken, 
6626                     ulColdMethodFlags, 
6627                     GetClrInstanceId(),
6628                     rejitID);
6629             }
6630         }
6631     }
6632     else
6633     {
6634         _ASSERTE((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoad) ||
6635             (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnload) ||
6636             (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodDCStart) ||
6637             (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodDCEnd) ||
6638             (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodLoad) ||
6639             (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodUnload) ||
6640             (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCStart) ||
6641             (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCEnd));
6642     }
6643 }
6644
6645 //---------------------------------------------------------------------------------------
6646 //
6647 // Fires the IL-to-native map event for JITted methods.  This is used for the runtime,
6648 // rundown start, and rundown end events that include the il-to-native map information
6649 //
6650 // Arguments:
6651 //      pMethodDesc - MethodDesc for which we'll fire the map event
6652 //      dwEventOptions - Options that tells us, in the rundown case, whether we're
6653 //                       supposed to fire the start or end rundown events.
6654 //
6655
6656 // static
6657 VOID ETW::MethodLog::SendMethodILToNativeMapEvent(MethodDesc * pMethodDesc, DWORD dwEventOptions, SIZE_T pCode, ReJITID rejitID)
6658 {
6659     CONTRACTL
6660     {
6661         THROWS;
6662         GC_NOTRIGGER;
6663         SO_NOT_MAINLINE;
6664     }
6665     CONTRACTL_END;
6666
6667     // This is the limit on how big the il-to-native map can get, as measured by number
6668     // of entries in each parallel array (IL offset array and native offset array). 
6669     // This number was chosen to ensure the overall event stays under the Windows limit
6670     // of 64K
6671     const USHORT kMapEntriesMax = 7000;
6672
6673     if (pMethodDesc == NULL)
6674         return;
6675
6676     if (pMethodDesc->HasClassOrMethodInstantiation() && pMethodDesc->IsTypicalMethodDefinition())
6677         return;
6678
6679     // g_pDebugInterface is initialized on startup on desktop CLR, regardless of whether a debugger
6680     // or profiler is loaded.  So it should always be available.
6681     _ASSERTE(g_pDebugInterface != NULL);
6682
6683     ULONGLONG ullMethodIdentifier = (ULONGLONG)pMethodDesc;
6684
6685     USHORT cMap;
6686     NewArrayHolder<UINT> rguiILOffset;
6687     NewArrayHolder<UINT> rguiNativeOffset;
6688
6689     HRESULT hr = g_pDebugInterface->GetILToNativeMappingIntoArrays(
6690         pMethodDesc,
6691         pCode,
6692         kMapEntriesMax,
6693         &cMap,
6694         &rguiILOffset,
6695         &rguiNativeOffset);
6696     if (FAILED(hr))
6697         return;
6698
6699     // Runtime provider.
6700     // 
6701     // This macro already checks for the JittedMethodILToNativeMapKeyword before
6702     // choosing to fire the event
6703     if ((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodILToNativeMap) != 0)
6704     {
6705         FireEtwMethodILToNativeMap(
6706             ullMethodIdentifier, 
6707             rejitID,
6708             0,          // Extent:  This event is only sent for JITted (not NGENd) methods, and
6709             //          currently there is only one extent (hot) for JITted methods.
6710             cMap,
6711             rguiILOffset,
6712             rguiNativeOffset,
6713             GetClrInstanceId());
6714     }
6715
6716     // Rundown provider
6717     // 
6718     // These macros already check for the JittedMethodILToNativeMapRundownKeyword
6719     // before choosing to fire the event--we further check our options to see if we
6720     // should fire the Start and / or End flavor of the event (since the keyword alone
6721     // is insufficient to distinguish these).
6722     // 
6723     // (for an explanation of the parameters see the FireEtwMethodILToNativeMap call above)
6724     if ((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::MethodDCStartILToNativeMap) != 0)
6725         FireEtwMethodDCStartILToNativeMap(ullMethodIdentifier, 0, 0, cMap, rguiILOffset, rguiNativeOffset, GetClrInstanceId());
6726     if ((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::MethodDCEndILToNativeMap) != 0)
6727         FireEtwMethodDCEndILToNativeMap(ullMethodIdentifier, 0, 0, cMap, rguiILOffset, rguiNativeOffset, GetClrInstanceId());
6728 }
6729
6730
6731 VOID ETW::MethodLog::SendHelperEvent(ULONGLONG ullHelperStartAddress, ULONG ulHelperSize, LPCWSTR pHelperName)
6732 {
6733     WRAPPER_NO_CONTRACT;
6734     if(pHelperName)
6735     {
6736          PCWSTR szDtraceOutput1=W("");
6737          ULONG methodFlags = ETW::MethodLog::MethodStructs::JitHelperMethod; // helper flag set
6738          FireEtwMethodLoadVerbose_V1(ullHelperStartAddress, 
6739                                      0, 
6740                                      ullHelperStartAddress, 
6741                                      ulHelperSize, 
6742                                      0, 
6743                                      methodFlags, 
6744                                      NULL,
6745                                      pHelperName, 
6746                                      NULL,
6747                                      GetClrInstanceId());
6748     }
6749 }
6750
6751
6752 /****************************************************************************/
6753 /* This routine sends back method events of type 'dwEventOptions', for all 
6754    NGEN methods in pModule */
6755 /****************************************************************************/
6756 VOID ETW::MethodLog::SendEventsForNgenMethods(Module *pModule, DWORD dwEventOptions)
6757 {
6758     CONTRACTL {
6759         THROWS;
6760         GC_TRIGGERS;
6761     } CONTRACTL_END;
6762
6763 #ifdef FEATURE_PREJIT
6764     if (!pModule)
6765         return;
6766
6767 #ifdef FEATURE_READYTORUN
6768     if (pModule->IsReadyToRun())
6769     {
6770         ReadyToRunInfo::MethodIterator mi(pModule->GetReadyToRunInfo());
6771         while (mi.Next())
6772         {
6773             // Call GetMethodDesc_NoRestore instead of GetMethodDesc to avoid restoring methods at shutdown.
6774             MethodDesc *hotDesc = (MethodDesc *)mi.GetMethodDesc_NoRestore();
6775             if (hotDesc != NULL)
6776             {
6777                 ETW::MethodLog::SendMethodEvent(hotDesc, dwEventOptions, FALSE);
6778             }
6779         }
6780
6781         return;
6782     }
6783 #endif // FEATURE_READYTORUN
6784     if (pModule->HasNativeImage())
6785     {
6786         MethodIterator mi(pModule);
6787
6788         while (mi.Next())
6789         {
6790             MethodDesc *hotDesc = (MethodDesc *)mi.GetMethodDesc();
6791             ETW::MethodLog::SendMethodEvent(hotDesc, dwEventOptions, FALSE);
6792         }
6793     }
6794 #endif // FEATURE_PREJIT
6795 }
6796
6797 // Called be ETW::MethodLog::SendEventsForJitMethods
6798 // Sends the ETW events once our caller determines whether or not rejit locks can be acquired
6799 VOID ETW::MethodLog::SendEventsForJitMethodsHelper(BaseDomain *pDomainFilter,
6800                                                    LoaderAllocator *pLoaderAllocatorFilter,
6801                                                    DWORD dwEventOptions,
6802                                                    BOOL fLoadOrDCStart,
6803                                                    BOOL fUnloadOrDCEnd,
6804                                                    BOOL fSendMethodEvent,
6805                                                    BOOL fSendILToNativeMapEvent,
6806                                                    BOOL fGetReJitIDs)
6807 {
6808     CONTRACTL{
6809         THROWS;
6810         GC_NOTRIGGER;
6811     } CONTRACTL_END;
6812
6813     EEJitManager::CodeHeapIterator heapIterator(pDomainFilter, pLoaderAllocatorFilter);
6814     while (heapIterator.Next())
6815     {
6816         MethodDesc * pMD = heapIterator.GetMethod();
6817         if (pMD == NULL)
6818             continue;
6819
6820         TADDR codeStart = heapIterator.GetMethodCode();
6821
6822         // Grab rejitID from the rejit manager. In some cases, such as collectible loader
6823         // allocators, we don't support rejit so we need to short circuit the call.
6824         // This also allows our caller to avoid having to pre-enter the rejit
6825         // manager locks.
6826         // see code:#TableLockHolder
6827         ReJITID rejitID =
6828             fGetReJitIDs ? ReJitManager::GetReJitIdNoLock(pMD, codeStart) : 0;
6829
6830         // There are small windows of time where the heap iterator may come across a
6831         // codeStart that is not yet published to the MethodDesc. This may happen if
6832         // we're JITting the method right now on another thread, and have not completed
6833         // yet. Detect the race, and skip the method if appropriate. (If rejitID is
6834         // nonzero, there is no race, as GetReJitIdNoLock will not return a nonzero
6835         // rejitID if the codeStart has not yet been published for that rejitted version
6836         // of the method.) This check also catches recompilations due to EnC, which we do
6837         // not want to issue events for, in order to ensure xperf's assumption that
6838         // MethodDesc* + ReJITID + extent (hot vs. cold) form a unique key for code
6839         // ranges of methods
6840         if ((rejitID == 0) && (codeStart != PCODEToPINSTR(pMD->GetNativeCode())))
6841             continue;
6842
6843         // When we're called to announce loads, then the methodload event itself must
6844         // precede any supplemental events, so that the method load or method jitting
6845         // event is the first event the profiler sees for that MethodID (and not, say,
6846         // the MethodILToNativeMap event.)
6847         if (fLoadOrDCStart)
6848         {
6849             if (fSendMethodEvent)
6850             {
6851                 ETW::MethodLog::SendMethodEvent(
6852                     pMD,
6853                     dwEventOptions,
6854                     TRUE,           // bIsJit
6855                     NULL,           // namespaceOrClassName
6856                     NULL,           // methodName
6857                     NULL,           // methodSignature
6858                     codeStart,
6859                     rejitID);
6860             }
6861         }
6862
6863         // Send any supplemental events requested for this MethodID
6864         if (fSendILToNativeMapEvent)
6865             ETW::MethodLog::SendMethodILToNativeMapEvent(pMD, dwEventOptions, codeStart, rejitID);
6866
6867         // When we're called to announce unloads, then the methodunload event itself must
6868         // come after any supplemental events, so that the method unload event is the
6869         // last event the profiler sees for this MethodID
6870         if (fUnloadOrDCEnd)
6871         {
6872             if (fSendMethodEvent)
6873             {
6874                 ETW::MethodLog::SendMethodEvent(
6875                     pMD,
6876                     dwEventOptions,
6877                     TRUE,           // bIsJit
6878                     NULL,           // namespaceOrClassName
6879                     NULL,           // methodName
6880                     NULL,           // methodSignature
6881                     codeStart,
6882                     rejitID);
6883             }
6884         }
6885     }
6886 }
6887
6888 /****************************************************************************/
6889 /* This routine sends back method events of type 'dwEventOptions', for all 
6890    JITed methods in either a given LoaderAllocator (if pLoaderAllocatorFilter is non NULL) 
6891    or in a given Domain (if pDomainFilter is non NULL) or for
6892    all methods (if both filters are null) */ 
6893 /****************************************************************************/
6894 // Code review indicates this method is never called with both filters NULL. Ideally we would
6895 // assert this and change the comment above, but given I am making a change late in the release I am being cautious
6896 VOID ETW::MethodLog::SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAllocator *pLoaderAllocatorFilter, DWORD dwEventOptions)
6897 {
6898     CONTRACTL {
6899         NOTHROW;
6900         GC_TRIGGERS;
6901     } CONTRACTL_END;
6902
6903 #if !defined(DACCESS_COMPILE)
6904     EX_TRY
6905     {
6906         // This is only called for JITted methods loading xor unloading
6907         BOOL fLoadOrDCStart = ((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoadOrDCStartAny) != 0);
6908         BOOL fUnloadOrDCEnd = ((dwEventOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnloadOrDCEndAny) != 0);
6909         _ASSERTE((fLoadOrDCStart || fUnloadOrDCEnd) && !(fLoadOrDCStart && fUnloadOrDCEnd));
6910
6911         BOOL fSendMethodEvent =
6912             (dwEventOptions & 
6913                 (ETW::EnumerationLog::EnumerationStructs::JitMethodLoad |
6914                 ETW::EnumerationLog::EnumerationStructs::JitMethodDCStart |
6915                 ETW::EnumerationLog::EnumerationStructs::JitMethodUnload |
6916                 ETW::EnumerationLog::EnumerationStructs::JitMethodDCEnd)) != 0;
6917
6918         BOOL fSendILToNativeMapEvent =
6919             (dwEventOptions & 
6920                 (ETW::EnumerationLog::EnumerationStructs::MethodDCStartILToNativeMap |
6921                 ETW::EnumerationLog::EnumerationStructs::MethodDCEndILToNativeMap)) != 0;
6922
6923         if (fSendILToNativeMapEvent)
6924         {
6925             // The call to SendMethodILToNativeMapEvent assumes that the debugger's lazy
6926             // data has already been initialized, to ensure we don't try to do the lazy init
6927             // while under the implicit, notrigger CodeHeapIterator lock below.
6928
6929             // g_pDebugInterface is initialized on startup on desktop CLR, regardless of whether a debugger
6930             // or profiler is loaded.  So it should always be available.
6931             _ASSERTE(g_pDebugInterface != NULL);
6932             g_pDebugInterface->InitializeLazyDataIfNecessary();
6933         }
6934
6935         // #TableLockHolder:
6936         // 
6937         // A word about ReJitManager::TableLockHolder... As we enumerate through the functions,
6938         // we may need to grab their ReJITIDs. The ReJitManager grabs its table Crst in order to
6939         // fetch these. However, several other kinds of locks are being taken during this
6940         // enumeration, such as the SystemDomain lock and the EEJitManager::CodeHeapIterator's
6941         // lock. In order to avoid lock-leveling issues, we grab the appropriate ReJitManager
6942         // table locks after SystemDomain and before CodeHeapIterator. In particular, we need to
6943         // grab the SharedDomain's ReJitManager table lock as well as the specific AppDomain's
6944         // ReJitManager table lock for the current AppDomain we're iterating. Why the SharedDomain's
6945         // ReJitManager lock? For any given AppDomain we're iterating over, the MethodDescs we
6946         // find may be managed by that AppDomain's ReJitManger OR the SharedDomain's ReJitManager.
6947         // (This is due to generics and whether given instantiations may be shared based on their
6948         // arguments.) Therefore, we proactively take the SharedDomain's ReJitManager's table
6949         // lock up front, and then individually take the appropriate AppDomain's ReJitManager's
6950         // table lock that corresponds to the domain or module we're currently iterating over.
6951         //
6952
6953         // We only support getting rejit IDs when filtering by domain.
6954         if (pDomainFilter)
6955         {
6956             CodeVersionManager::TableLockHolder lkRejitMgrSharedDomain(SharedDomain::GetDomain()->GetCodeVersionManager());
6957             CodeVersionManager::TableLockHolder lkRejitMgrModule(pDomainFilter->GetCodeVersionManager());
6958             SendEventsForJitMethodsHelper(pDomainFilter,
6959                 pLoaderAllocatorFilter,
6960                 dwEventOptions,
6961                 fLoadOrDCStart,
6962                 fUnloadOrDCEnd,
6963                 fSendMethodEvent,
6964                 fSendILToNativeMapEvent,
6965                 TRUE);
6966         }
6967         else
6968         {
6969             SendEventsForJitMethodsHelper(pDomainFilter,
6970                 pLoaderAllocatorFilter,
6971                 dwEventOptions,
6972                 fLoadOrDCStart,
6973                 fUnloadOrDCEnd,
6974                 fSendMethodEvent,
6975                 fSendILToNativeMapEvent,
6976                 FALSE);
6977         }
6978     } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
6979 #endif // !DACCESS_COMPILE
6980 }
6981
6982 //---------------------------------------------------------------------------------------
6983 //
6984 // Wrapper around IterateDomain, which locks the AppDomain to be <
6985 // STAGE_FINALIZED until the iteration is complete.
6986 //
6987 // Arguments:
6988 //      pAppDomain - AppDomain to iterate
6989 //      enumerationOptions - Flags indicating what to enumerate.  Just passed
6990 //         straight through to IterateDomain
6991 //
6992 VOID ETW::EnumerationLog::IterateAppDomain(AppDomain * pAppDomain, DWORD enumerationOptions)
6993 {
6994     CONTRACTL 
6995     {
6996         THROWS;
6997         GC_TRIGGERS;
6998         PRECONDITION(pAppDomain != NULL);
6999     }
7000     CONTRACTL_END;
7001
7002     // Hold the system domain lock during the entire iteration, so we can
7003     // ensure the App Domain does not get finalized until we're all done
7004     SystemDomain::LockHolder lh;
7005
7006     // Now it's safe to do the iteration
7007     IterateDomain(pAppDomain, enumerationOptions);
7008 }
7009
7010 /********************************************************************************/
7011 /* This routine fires ETW events for 
7012    Domain, 
7013    Assemblies in them, 
7014    DomainModule's in them, 
7015    Modules in them, 
7016    JIT methods in them,
7017    and the NGEN methods in them
7018    based on enumerationOptions.*/
7019 /********************************************************************************/
7020 VOID ETW::EnumerationLog::IterateDomain(BaseDomain *pDomain, DWORD enumerationOptions)
7021 {
7022     CONTRACTL {
7023         THROWS;
7024         GC_TRIGGERS;
7025         PRECONDITION(pDomain != NULL);
7026     } CONTRACTL_END;
7027     
7028 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
7029     // Do not call IterateDomain() directly with an AppDomain.  Use
7030     // IterateAppDomain(), whch wraps this function with a hold on the
7031     // SystemDomain lock, which ensures pDomain's type data doesn't disappear
7032     // on us.
7033     if (pDomain->IsAppDomain())
7034     {
7035         _ASSERTE(SystemDomain::IsUnderDomainLock());
7036     }
7037 #endif // defined(_DEBUG) && !defined(DACCESS_COMPILE)
7038
7039     EX_TRY
7040     {    
7041         // DC Start events for Domain
7042         if(enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)
7043         {
7044             ETW::LoaderLog::SendDomainEvent(pDomain, enumerationOptions);
7045         }
7046     
7047         // DC End or Unload Jit Method events
7048         if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnloadOrDCEndAny)
7049         {
7050             ETW::MethodLog::SendEventsForJitMethods(pDomain, NULL, enumerationOptions);
7051         }
7052     
7053         if (pDomain->IsAppDomain())
7054         {
7055             AppDomain::AssemblyIterator assemblyIterator = pDomain->AsAppDomain()->IterateAssembliesEx(
7056                 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
7057             CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7058             while (assemblyIterator.Next(pDomainAssembly.This()))
7059             {
7060                 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
7061                 BOOL bIsDomainNeutral = pAssembly->IsDomainNeutral();
7062                 if (bIsDomainNeutral)
7063                     continue;
7064                 if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)
7065                 {
7066                     ETW::EnumerationLog::IterateAssembly(pAssembly, enumerationOptions);
7067                 }
7068                 
7069                 DomainModuleIterator domainModuleIterator = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
7070                 while (domainModuleIterator.Next()) 
7071                 {
7072                     Module * pModule = domainModuleIterator.GetModule();
7073                     ETW::EnumerationLog::IterateModule(pModule, enumerationOptions);
7074                 }
7075
7076                 if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) ||
7077                    (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload))
7078                 {
7079                     ETW::EnumerationLog::IterateAssembly(pAssembly, enumerationOptions);
7080                 }
7081             }
7082         }
7083         else
7084         {
7085             SharedDomain::SharedAssemblyIterator sharedDomainIterator;
7086             while (sharedDomainIterator.Next())
7087             {
7088                 Assembly * pAssembly = sharedDomainIterator.GetAssembly();
7089                 if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)
7090                 {
7091                     ETW::EnumerationLog::IterateAssembly(pAssembly, enumerationOptions);
7092                 }
7093
7094                 ModuleIterator domainModuleIterator = pAssembly->IterateModules();
7095                 while (domainModuleIterator.Next()) 
7096                 {
7097                     Module * pModule = domainModuleIterator.GetModule();
7098                     ETW::EnumerationLog::IterateModule(pModule, enumerationOptions);
7099                 }
7100
7101                 if ((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) || 
7102                     (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload))
7103                 {
7104                     ETW::EnumerationLog::IterateAssembly(pAssembly, enumerationOptions);
7105                 }
7106             }
7107         }
7108         
7109         // DC Start or Load Jit Method events
7110         if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoadOrDCStartAny)
7111         {
7112             ETW::MethodLog::SendEventsForJitMethods(pDomain, NULL, enumerationOptions);
7113         }
7114     
7115         // DC End or Unload events for Domain
7116         if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) || 
7117            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload))
7118         {
7119             ETW::LoaderLog::SendDomainEvent(pDomain, enumerationOptions);
7120         }
7121     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
7122 }
7123
7124
7125 /********************************************************************************/
7126 /* This routine fires ETW events for 
7127    Assembly in LoaderAllocator, 
7128    DomainModule's in them, 
7129    Modules in them, 
7130    JIT methods in them,
7131    and the NGEN methods in them
7132    based on enumerationOptions.*/
7133 /********************************************************************************/
7134 VOID ETW::EnumerationLog::IterateCollectibleLoaderAllocator(AssemblyLoaderAllocator *pLoaderAllocator, DWORD enumerationOptions)
7135 {
7136     CONTRACTL {
7137         THROWS;
7138         GC_TRIGGERS;
7139         PRECONDITION(pLoaderAllocator != NULL);
7140     } CONTRACTL_END;
7141     
7142     EX_TRY
7143     {    
7144         // Unload Jit Method events
7145         if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnload)
7146         {
7147             ETW::MethodLog::SendEventsForJitMethods(NULL, pLoaderAllocator, enumerationOptions);
7148         }
7149     
7150         // Iterate on all DomainAssembly loaded from the same AssemblyLoaderAllocator
7151         DomainAssemblyIterator domainAssemblyIt = pLoaderAllocator->Id()->GetDomainAssemblyIterator();
7152         while (!domainAssemblyIt.end())
7153         {
7154             Assembly *pAssembly = domainAssemblyIt->GetAssembly(); // TODO: handle iterator
7155             _ASSERTE(!pAssembly->IsDomainNeutral()); // Collectible Assemblies are not domain neutral.
7156
7157             DomainModuleIterator domainModuleIterator = domainAssemblyIt->IterateModules(kModIterIncludeLoaded);
7158             while (domainModuleIterator.Next())
7159             {
7160                 Module *pModule = domainModuleIterator.GetModule();
7161                 ETW::EnumerationLog::IterateModule(pModule, enumerationOptions);
7162             }
7163
7164             if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload)
7165             {
7166                 ETW::EnumerationLog::IterateAssembly(pAssembly, enumerationOptions);
7167             }
7168
7169             domainAssemblyIt++;
7170         }
7171
7172         // Load Jit Method events
7173         if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoad)
7174         {
7175             ETW::MethodLog::SendEventsForJitMethods(NULL, pLoaderAllocator, enumerationOptions);
7176         }
7177     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
7178 }
7179
7180 /********************************************************************************/
7181 /* This routine fires ETW events for Assembly and the DomainModule's in them
7182    based on enumerationOptions.*/
7183 /********************************************************************************/
7184 VOID ETW::EnumerationLog::IterateAssembly(Assembly *pAssembly, DWORD enumerationOptions)
7185 {
7186     CONTRACTL {
7187         THROWS;
7188         GC_TRIGGERS;
7189         PRECONDITION(pAssembly != NULL);
7190     } CONTRACTL_END;
7191     
7192     EX_TRY
7193     {
7194         // DC Start events for Assembly
7195         if(enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)
7196         {
7197             ETW::LoaderLog::SendAssemblyEvent(pAssembly, enumerationOptions);
7198         }
7199         
7200         // DC Start, DCEnd, events for DomainModule
7201         if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) ||
7202            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart))
7203         {
7204             if(pAssembly->GetDomain()->IsAppDomain())
7205             {
7206                 DomainModuleIterator dmIterator = pAssembly->FindDomainAssembly(pAssembly->GetDomain()->AsAppDomain())->IterateModules(kModIterIncludeLoaded);
7207                 while (dmIterator.Next()) 
7208                 {
7209                     ETW::LoaderLog::SendModuleEvent(dmIterator.GetModule(), enumerationOptions, TRUE);
7210                 }
7211             }
7212         }
7213
7214         // DC End or Unload events for Assembly
7215         if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) ||
7216            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload))
7217         {
7218             ETW::LoaderLog::SendAssemblyEvent(pAssembly, enumerationOptions);
7219         }
7220     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
7221 }
7222
7223 /********************************************************************************/
7224 /* This routine fires ETW events for Module, their range information and the NGEN methods in them
7225    based on enumerationOptions.*/
7226 /********************************************************************************/
7227 VOID ETW::EnumerationLog::IterateModule(Module *pModule, DWORD enumerationOptions)
7228 {
7229     CONTRACTL {
7230         THROWS;
7231         GC_TRIGGERS;
7232         PRECONDITION(pModule != NULL);
7233     } CONTRACTL_END;
7234     
7235     EX_TRY
7236     {    
7237         // DC Start events for Module
7238         if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart) ||
7239            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCStart))
7240         {
7241             ETW::LoaderLog::SendModuleEvent(pModule, enumerationOptions);
7242         }
7243         
7244         // DC Start or Load or DC End or Unload Ngen Method events
7245         if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodLoad) || 
7246            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCStart) || 
7247            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodUnload) || 
7248            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::NgenMethodDCEnd))
7249         {
7250             ETW::MethodLog::SendEventsForNgenMethods(pModule, enumerationOptions);
7251         }            
7252         
7253         // DC End or Unload events for Module
7254         if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) || 
7255            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleUnload) ||
7256            (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeDCEnd))
7257         {
7258             ETW::LoaderLog::SendModuleEvent(pModule, enumerationOptions);
7259         }
7260
7261         // If we're logging types, then update the internal Type hash table to account
7262         // for the module's unloading
7263         if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::TypeUnload)
7264         {
7265             ETW::TypeSystemLog::OnModuleUnload(pModule);
7266         }
7267         
7268         // ModuleRangeLoadPrivate events for module range information from attach/detach scenarios
7269         if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, 
7270                                          TRACE_LEVEL_INFORMATION, 
7271                                          CLR_PERFTRACK_PRIVATE_KEYWORD) && 
7272             (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::ModuleRangeLoadPrivate))
7273         {
7274             ETW::LoaderLog::SendModuleEvent(pModule, enumerationOptions);
7275         }
7276     } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
7277 }
7278
7279 //---------------------------------------------------------------------------------------
7280 //
7281 // This routine sends back domain, assembly, module and method events based on
7282 // enumerationOptions.
7283 //
7284 // Arguments:
7285 //      * moduleFilter - if non-NULL, events from only moduleFilter module are reported
7286 //      * domainFilter - if non-NULL, events from only domainFilter domain are reported
7287 //      * enumerationOptions - Flags from ETW::EnumerationLog::EnumerationStructs which
7288 //          describe which events should be sent.
7289 //
7290 // Notes:
7291 //     * if all filter args are NULL, events from all domains are reported
7292 //     
7293 //
7294
7295 // static
7296 VOID ETW::EnumerationLog::EnumerationHelper(Module *moduleFilter, BaseDomain *domainFilter, DWORD enumerationOptions)
7297 {
7298     CONTRACTL {
7299         THROWS;
7300         GC_TRIGGERS;
7301     } CONTRACTL_END;
7302     
7303     // Disable IBC logging during ETW enumeration since we call a lot of functionality
7304     // that does logging and causes problems in the shutdown path due to critical
7305     // section access for IBC logging
7306     IBCLoggingDisabler disableLogging;
7307
7308     if(moduleFilter)
7309     {
7310         // Iteratate modules first because their number is ussualy smaller then the number of methods. 
7311         // Thus hitting a timeout due to a large number of methods will not affect modules rundown.tf g
7312         ETW::EnumerationLog::IterateModule(moduleFilter, enumerationOptions);
7313
7314         // As best I can tell from code review, these if statements below are never true. There is
7315         // only one caller to this method that specifies a moduleFilter, ETW::LoaderLog::ModuleLoad.
7316         // That method never specifies these flags. Because it is late in a release cycle I am not
7317         // making a change, but if you see this comment early in the next release cycle consider
7318         // deleting this apparently dead code.
7319
7320         // DC End or Unload Jit Method events from all Domains
7321         if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnloadOrDCEndAny)
7322         {
7323             ETW::MethodLog::SendEventsForJitMethods(NULL, NULL, enumerationOptions);
7324         }
7325
7326         // DC Start or Load Jit Method events from all Domains
7327         if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodLoadOrDCStartAny)
7328         {
7329             ETW::MethodLog::SendEventsForJitMethods(NULL, NULL, enumerationOptions);
7330         }
7331     }
7332     else
7333     {
7334         if(domainFilter)
7335         {
7336             if(domainFilter->IsAppDomain())
7337             {
7338                 ETW::EnumerationLog::IterateAppDomain(domainFilter->AsAppDomain(), enumerationOptions);
7339             }
7340             else
7341             {
7342                 ETW::EnumerationLog::IterateDomain(domainFilter, enumerationOptions);
7343             }
7344         }
7345         else 
7346         {
7347             AppDomainIterator appDomainIterator(FALSE);
7348             while(appDomainIterator.Next())
7349             {
7350                 AppDomain *pDomain = appDomainIterator.GetDomain();
7351                 if (pDomain != NULL)
7352                 {
7353                     ETW::EnumerationLog::IterateAppDomain(pDomain, enumerationOptions);
7354                 }
7355             }
7356
7357             ETW::EnumerationLog::IterateDomain(SharedDomain::GetDomain(), enumerationOptions);
7358         }    
7359     }    
7360 }
7361
7362 #endif // !FEATURE_REDHAWK
7363
7364 #ifdef FEATURE_PERFTRACING
7365 #include "eventpipe.h"
7366 bool EventPipeHelper::Enabled()
7367 {
7368     LIMITED_METHOD_CONTRACT;
7369     return EventPipe::Enabled();
7370 }
7371 #endif // FEATURE_PERFTRACING