2121#include " threadstore.h"
2222#include " threadstore.inl"
2323
24+ #include < minipal/utf8.h>
25+
2426EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context = { W (" Microsoft-Windows-DotNETRuntime" ), 0 , false , 0 };
2527DOTNET_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context = {
2628#ifdef FEATURE_ETW
@@ -29,6 +31,14 @@ DOTNET_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context = {
2931 MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context
3032};
3133
34+ EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context = { W (" Microsoft-Windows-DotNETRuntimeRundown" ), 0 , false , 0 };
35+ DOTNET_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context = {
36+ #ifdef FEATURE_ETW
37+ &MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
38+ #endif
39+ MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context
40+ };
41+
3242EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context = { W (" Microsoft-Windows-DotNETRuntimePrivate" ), 0 , false , 0 };
3343DOTNET_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context = {
3444#ifdef FEATURE_ETW
@@ -42,6 +52,11 @@ bool IsRuntimeProviderEnabled(uint8_t level, uint64_t keyword)
4252 return RUNTIME_PROVIDER_CATEGORY_ENABLED (level, keyword);
4353}
4454
55+ bool IsRuntimeRundownProviderEnabled (uint8_t level, uint64_t keyword)
56+ {
57+ return RUNTIME_RUNDOWN_PROVIDER_CATEGORY_ENABLED (level, keyword);
58+ }
59+
4560volatile LONGLONG ETW::GCLog::s_l64LastClientSequenceNumber = 0 ;
4661
4762// ---------------------------------------------------------------------------------------
@@ -81,13 +96,16 @@ void EventTracing_Initialize()
8196#ifdef FEATURE_ETW
8297 MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context.IsEnabled = FALSE ;
8398 MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context.IsEnabled = FALSE ;
99+ MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context.IsEnabled = FALSE ;
84100
85101 // Register the ETW providers with the system.
86102 EventRegisterMicrosoft_Windows_DotNETRuntimePrivate ();
87103 EventRegisterMicrosoft_Windows_DotNETRuntime ();
104+ EventRegisterMicrosoft_Windows_DotNETRuntimeRundown ();
88105
89106 MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context.RegistrationHandle = Microsoft_Windows_DotNETRuntimePrivateHandle;
90107 MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context.RegistrationHandle = Microsoft_Windows_DotNETRuntimeHandle;
108+ MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context.RegistrationHandle = Microsoft_Windows_DotNETRuntimeRundownHandle;
91109#endif // FEATURE_ETW
92110}
93111
@@ -187,9 +205,13 @@ void EtwCallbackCommon(
187205 case DotNETRuntime:
188206 ctxToUpdate = &MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context;
189207 break ;
208+ case DotNETRuntimeRundown:
209+ ctxToUpdate = &MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context;
210+ break ;
190211 case DotNETRuntimePrivate:
191212 ctxToUpdate = &MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context;
192213 break ;
214+
193215 default :
194216 _ASSERTE (!" EtwCallbackCommon was called with invalid context" );
195217 return ;
@@ -261,7 +283,7 @@ void EtwCallbackCommon(
261283
262284void EtwCallback (
263285 const GUID * /* SourceId*/ ,
264- uint32_t IsEnabled ,
286+ uint32_t ControlCode ,
265287 uint8_t Level,
266288 uint64_t MatchAnyKeyword,
267289 uint64_t MatchAllKeyword,
@@ -272,16 +294,27 @@ void EtwCallback(
272294 if (context == NULL )
273295 return ;
274296
297+ // A manifest based provider can be enabled to multiple event tracing sessions
298+ // As long as there is atleast 1 enabled session, IsEnabled will be TRUE
299+ // Since classic providers can be enabled to only a single session,
300+ // IsEnabled will be TRUE when it is enabled and FALSE when disabled
301+ BOOL bEnabled =
302+ ((ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER) ||
303+ (ControlCode == EVENT_CONTROL_CODE_CAPTURE_STATE));
304+
275305 context->Level = Level;
276306 context->MatchAnyKeyword = MatchAnyKeyword;
277307 context->MatchAllKeyword = MatchAllKeyword;
278- context->IsEnabled = IsEnabled ;
308+ context->IsEnabled = bEnabled ;
279309
280310 CallbackProviderIndex providerIndex = DotNETRuntime;
281311 DOTNET_TRACE_CONTEXT providerContext = MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context;
282312 if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeHandle) {
283313 providerIndex = DotNETRuntime;
284314 providerContext = MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context;
315+ } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeRundownHandle) {
316+ providerIndex = DotNETRuntimeRundown;
317+ providerContext = MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context;
285318 } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimePrivateHandle) {
286319 providerIndex = DotNETRuntimePrivate;
287320 providerContext = MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context;
@@ -290,20 +323,128 @@ void EtwCallback(
290323 return ;
291324 }
292325
293- EtwCallbackCommon (providerIndex, IsEnabled , Level, MatchAnyKeyword, FilterData, EtwSessionChangeUnknown);
326+ EtwCallbackCommon (providerIndex, ControlCode , Level, MatchAnyKeyword, FilterData, EtwSessionChangeUnknown);
294327
295- if (IsEnabled &&
296- (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimePrivateHandle) &&
297- GCHeapUtilities::IsGCHeapInitialized ())
328+ if (bEnabled)
298329 {
299- FireEtwGCSettings_V1 (GCHeapUtilities::GetGCHeap ()->GetValidSegmentSize (FALSE ),
300- GCHeapUtilities::GetGCHeap ()->GetValidSegmentSize (TRUE ),
301- GCHeapUtilities::IsServerHeap (), GetClrInstanceId ());
302- GCHeapUtilities::GetGCHeap ()->DiagTraceGCSegments ();
330+ if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimePrivateHandle &&
331+ GCHeapUtilities::IsGCHeapInitialized ())
332+ {
333+ FireEtwGCSettings_V1 (GCHeapUtilities::GetGCHeap ()->GetValidSegmentSize (FALSE ),
334+ GCHeapUtilities::GetGCHeap ()->GetValidSegmentSize (TRUE ),
335+ GCHeapUtilities::IsServerHeap (), GetClrInstanceId ());
336+ GCHeapUtilities::GetGCHeap ()->DiagTraceGCSegments ();
337+ }
338+
339+ if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeRundownHandle)
340+ {
341+ if (IsRuntimeRundownProviderEnabled (TRACE_LEVEL_INFORMATION, CLR_RUNDOWNEND_KEYWORD))
342+ ETW::EnumerationLog::EndRundown ();
343+ }
303344 }
304345}
346+
305347#endif // FEATURE_ETW
306348
349+ void ETW::LoaderLog::ModuleLoad (HANDLE pModule)
350+ {
351+ if (IsRuntimeProviderEnabled (TRACE_LEVEL_INFORMATION, KEYWORDZERO))
352+ {
353+ SendModuleEvent (pModule, ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad);
354+ }
355+ }
356+
357+ // ---------------------------------------------------------------------------------------
358+ //
359+ // send a module load/unload or rundown event and domainmodule load and rundown event
360+ //
361+ // Arguments:
362+ // * pModule - Module loading or unloading
363+ // * dwEventOptions - Bitmask of which events to fire
364+ //
365+ void ETW::LoaderLog::SendModuleEvent (HANDLE pModule, uint32_t dwEventOptions)
366+ {
367+ const WCHAR * wszModuleFileName = NULL ;
368+ const WCHAR * wszModuleILFileName = W (" " );
369+
370+ #if TARGET_WINDOWS
371+ PalGetModuleFileName (&wszModuleFileName, pModule);
372+ #else
373+ const char * wszModuleFileNameUtf8 = NULL ;
374+ uint32_t moduleFileNameCharCount = PalGetModuleFileName (&wszModuleFileNameUtf8, pModule);
375+ CHAR16_T wszModuleFileNameUnicode[1024 ];
376+ minipal_convert_utf8_to_utf16 (wszModuleFileNameUtf8, moduleFileNameCharCount, &wszModuleFileNameUnicode[0 ], ARRAY_SIZE (wszModuleFileNameUnicode), MINIPAL_MB_NO_REPLACE_INVALID_CHARS);
377+ wszModuleFileName = (const WCHAR *)&wszModuleFileNameUnicode[0 ];
378+ #endif
379+
380+ GUID nativeGuid;
381+ uint32_t dwAge;
382+ WCHAR wszPath[1024 ];
383+ PalGetPDBInfo (pModule, &nativeGuid, &dwAge, wszPath, ARRAY_SIZE (wszPath));
384+
385+ GUID zeroGuid = { 0 };
386+
387+ if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad)
388+ {
389+ FireEtwModuleLoad_V2 (
390+ ULONGLONG (pModule),
391+ 0 , // AssemblyID
392+ ETW::LoaderLog::LoaderStructs::NativeModule, // Module Flags
393+ 0 , // Reserved1,
394+ wszModuleILFileName, // ModuleILPath,
395+ wszModuleFileName, // ModuleNativePath,
396+ GetClrInstanceId (),
397+ &zeroGuid, // ManagedPdbSignature,
398+ 0 , // ManagedPdbAge,
399+ NULL , // ManagedPdbBuildPath,
400+ &nativeGuid, // NativePdbSignature,
401+ dwAge, // NativePdbAge,
402+ wszPath // NativePdbBuildPath,
403+ );
404+ }
405+ else if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd)
406+ {
407+ FireEtwModuleDCEnd_V2 (
408+ ULONGLONG (pModule),
409+ 0 , // AssemblyID
410+ ETW::LoaderLog::LoaderStructs::NativeModule, // Module Flags
411+ 0 , // Reserved1,
412+ wszModuleILFileName, // ModuleILPath,
413+ wszModuleFileName, // ModuleNativePath,
414+ GetClrInstanceId (),
415+ &zeroGuid, // ManagedPdbSignature,
416+ 0 , // ManagedPdbAge,
417+ NULL , // ManagedPdbBuildPath,
418+ &nativeGuid, // NativePdbSignature,
419+ dwAge, // NativePdbAge,
420+ wszPath // NativePdbBuildPath,
421+ );
422+ }
423+ else
424+ {
425+ ASSERT (0 );
426+ }
427+ }
428+
429+ /* *************************************************************************************/
430+ /* Called when ETW is turned OFF on an existing process .Will be used by the controller for end rundown*/
431+ /* *************************************************************************************/
432+ void ETW::EnumerationLog::EndRundown ()
433+ {
434+ if (IsRuntimeRundownProviderEnabled (TRACE_LEVEL_INFORMATION, CLR_RUNDOWNLOADER_KEYWORD))
435+ {
436+ // begin marker event will go to the rundown provider
437+ FireEtwDCEndInit_V1 (GetClrInstanceId ());
438+
439+ HANDLE pModule = PalGetModuleHandleFromPointer ((void *)&EndRundown);
440+
441+ LoaderLog::SendModuleEvent (pModule, EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd);
442+
443+ // end marker event will go to the rundown provider
444+ FireEtwDCEndComplete_V1 (GetClrInstanceId ());
445+ }
446+ }
447+
307448void EventPipeEtwCallbackDotNETRuntime (
308449 _In_ GUID * SourceId,
309450 _In_ ULONG ControlCode,
@@ -318,6 +459,20 @@ void EventPipeEtwCallbackDotNETRuntime(
318459 EtwCallbackCommon (DotNETRuntime, ControlCode, Level, MatchAnyKeyword, FilterData, change);
319460}
320461
462+ void EventPipeEtwCallbackDotNETRuntimeRundown (
463+ _In_ GUID * SourceId,
464+ _In_ ULONG ControlCode,
465+ _In_ unsigned char Level,
466+ _In_ ULONGLONG MatchAnyKeyword,
467+ _In_ ULONGLONG MatchAllKeyword,
468+ _In_opt_ EventFilterDescriptor* FilterData,
469+ _Inout_opt_ PVOID CallbackContext)
470+ {
471+ SessionChange change = SourceId == NULL ? EventPipeSessionDisable : EventPipeSessionEnable;
472+
473+ EtwCallbackCommon (DotNETRuntimeRundown, ControlCode, Level, MatchAnyKeyword, FilterData, change);
474+ }
475+
321476void EventPipeEtwCallbackDotNETRuntimePrivate (
322477 _In_ GUID * SourceId,
323478 _In_ ULONG ControlCode,
0 commit comments