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