diff --git a/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp b/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp index 0fc3881c53476e..ca79248b1ecaa4 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp +++ b/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp @@ -67,12 +67,16 @@ EXTERN_C uint64_t QCALLTYPE EventPipeInternal_Enable( if (configProviders) { for (uint32_t i = 0; i < numProviders; ++i) { + ep_char8_t *providerName = ep_rt_utf16_to_utf8_string (reinterpret_cast(nativeProviders[i].pProviderName)); + ep_char8_t *filterData = ep_rt_utf16_to_utf8_string (reinterpret_cast(nativeProviders[i].pFilterData)); ep_provider_config_init ( &configProviders[i], - ep_rt_utf16_to_utf8_string (reinterpret_cast(nativeProviders[i].pProviderName)), + providerName, nativeProviders[i].keywords, static_cast(nativeProviders[i].loggingLevel), - ep_rt_utf16_to_utf8_string (reinterpret_cast(nativeProviders[i].pFilterData))); + filterData); + ep_rt_utf8_string_free (providerName); + ep_rt_utf8_string_free (filterData); } } @@ -95,10 +99,8 @@ EXTERN_C uint64_t QCALLTYPE EventPipeInternal_Enable( ep_start_streaming(result); if (configProviders) { - for (uint32_t i = 0; i < numProviders; ++i) { - ep_rt_utf8_string_free ((ep_char8_t *)ep_provider_config_get_provider_name (&configProviders[i])); - ep_rt_utf8_string_free ((ep_char8_t *)ep_provider_config_get_filter_data (&configProviders[i])); - } + for (uint32_t i = 0; i < numProviders; ++i) + ep_provider_config_fini (&configProviders[i]); free(configProviders); } diff --git a/src/coreclr/vm/eventpipeadapter.h b/src/coreclr/vm/eventpipeadapter.h index f344d206629c12..6673a3abccd89a 100644 --- a/src/coreclr/vm/eventpipeadapter.h +++ b/src/coreclr/vm/eventpipeadapter.h @@ -40,12 +40,16 @@ class EventPipeProviderConfigurationAdapter final m_providerConfigsLen = providerConfigsLen; if (m_providerConfigs) { for (uint32_t i = 0; i < providerConfigsLen; ++i) { + ep_char8_t *providerName = ep_rt_utf16_to_utf8_string (reinterpret_cast(providerConfigs[i].providerName)); + ep_char8_t *filterData = ep_rt_utf16_to_utf8_string (reinterpret_cast(providerConfigs[i].filterData)); ep_provider_config_init ( &m_providerConfigs[i], - ep_rt_utf16_to_utf8_string (reinterpret_cast(providerConfigs[i].providerName)), + providerName, providerConfigs[i].keywords, static_cast(providerConfigs[i].loggingLevel), - ep_rt_utf16_to_utf8_string (reinterpret_cast(providerConfigs[i].filterData))); + filterData); + ep_rt_utf8_string_free (providerName); + ep_rt_utf8_string_free (filterData); } } } @@ -54,10 +58,8 @@ class EventPipeProviderConfigurationAdapter final { STATIC_CONTRACT_NOTHROW; if (m_providerConfigs) { - for (uint32_t i = 0; i < m_providerConfigsLen; ++i) { - ep_rt_utf8_string_free ((ep_char8_t *)ep_provider_config_get_provider_name (&m_providerConfigs[i])); - ep_rt_utf8_string_free ((ep_char8_t *)ep_provider_config_get_filter_data (&m_providerConfigs[i])); - } + for (uint32_t i = 0; i < m_providerConfigsLen; ++i) + ep_provider_config_fini(&m_providerConfigs[i]); delete [] m_providerConfigs; } } @@ -385,7 +387,9 @@ class EventPipeAdapter final ep_provider_config_get_provider_name (&config[0]), ep_provider_config_get_keywords (&config[0]), (EventPipeEventLevel)ep_provider_config_get_logging_level (&config[0]), - ep_provider_config_get_filter_data (&config[0])); + ep_provider_config_get_filter_data (&config[0]), + NULL, + NULL); } static HRESULT GetProviderName(const EventPipeProvider *provider, ULONG numNameChars, ULONG *numNameCharsOut, LPWSTR name) diff --git a/src/mono/mono/component/event_pipe.c b/src/mono/mono/component/event_pipe.c index ac591492eb2f0d..0c020405a97b15 100644 --- a/src/mono/mono/component/event_pipe.c +++ b/src/mono/mono/component/event_pipe.c @@ -151,19 +151,22 @@ event_pipe_enable ( IpcStream *stream, EventPipeSessionSynchronousCallback sync_callback) { - ERROR_DECL (error); EventPipeSessionID session_id = 0; EventPipeProviderConfiguration *config_providers = g_new0 (EventPipeProviderConfiguration, providers_len); if (config_providers) { for (guint32 i = 0; i < providers_len; ++i) { + ep_char8_t *provider_name = ep_rt_utf16_to_utf8_string ((const ep_char16_t *)(providers[i].provider_name)); + ep_char8_t *filter_data = ep_rt_utf16_to_utf8_string ((const ep_char16_t *)(providers[i].filter_data)); ep_provider_config_init ( &config_providers[i], - providers[i].provider_name ? mono_utf16_to_utf8 (providers[i].provider_name, g_utf16_len (providers[i].provider_name), error) : NULL, + provider_name, providers [i].keywords, (EventPipeEventLevel)providers [i].logging_level, - providers[i].filter_data ? mono_utf16_to_utf8 (providers[i].filter_data, g_utf16_len (providers[i].filter_data), error) : NULL); + filter_data); + ep_rt_utf8_string_free (provider_name); + ep_rt_utf8_string_free (filter_data); } } @@ -180,11 +183,8 @@ event_pipe_enable ( NULL); if (config_providers) { - for (guint32 i = 0; i < providers_len; ++i) { + for (guint32 i = 0; i < providers_len; ++i) ep_provider_config_fini (&config_providers[i]); - g_free ((ep_char8_t *)ep_provider_config_get_provider_name (&config_providers[i])); - g_free ((ep_char8_t *)ep_provider_config_get_filter_data (&config_providers[i])); - } } return session_id; diff --git a/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c b/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c index dcad1f2f88353c..ad2c671100cb7e 100644 --- a/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c +++ b/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c @@ -103,7 +103,8 @@ buffer_manager_init ( current_provider_config, 1, NULL, - NULL); + NULL, + 0); EP_LOCK_EXIT (section1) ep_raise_error_if_nok (*session != NULL); diff --git a/src/mono/mono/eventpipe/test/ep-buffer-tests.c b/src/mono/mono/eventpipe/test/ep-buffer-tests.c index d1eb3eb56f5d37..87aca21c2b8468 100644 --- a/src/mono/mono/eventpipe/test/ep-buffer-tests.c +++ b/src/mono/mono/eventpipe/test/ep-buffer-tests.c @@ -91,7 +91,8 @@ load_buffer_with_events_init ( current_provider_config, 1, NULL, - NULL); + NULL, + 0); EP_LOCK_EXIT (section1) ep_raise_error_if_nok (*session != NULL); diff --git a/src/mono/mono/eventpipe/test/ep-session-tests.c b/src/mono/mono/eventpipe/test/ep-session-tests.c index 0c2506eab62e0e..a5f49a37fa0546 100644 --- a/src/mono/mono/eventpipe/test/ep-session-tests.c +++ b/src/mono/mono/eventpipe/test/ep-session-tests.c @@ -51,7 +51,8 @@ test_create_delete_session (void) current_provider_config, 1, NULL, - NULL); + NULL, + 0); EP_LOCK_EXIT (section1) ep_raise_error_if_nok (test_session != NULL); @@ -93,7 +94,8 @@ test_add_session_providers (void) current_provider_config, 1, NULL, - NULL); + NULL, + 0); ep_raise_error_if_nok_holding_lock (test_session != NULL, section1); @@ -111,7 +113,7 @@ test_add_session_providers (void) test_location = 3; - test_session_provider = ep_session_provider_alloc (TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOGALWAYS, ""); + test_session_provider = ep_session_provider_alloc (TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOGALWAYS, "", NULL, NULL); ep_raise_error_if_nok (test_session_provider != NULL); test_location = 4; @@ -176,7 +178,8 @@ test_session_special_get_set (void) current_provider_config, 1, NULL, - NULL); + NULL, + 0); EP_LOCK_EXIT (section1) ep_raise_error_if_nok (test_session != NULL); diff --git a/src/mono/mono/eventpipe/test/ep-thread-tests.c b/src/mono/mono/eventpipe/test/ep-thread-tests.c index 77342b7633f250..c5acc665a1c5ac 100644 --- a/src/mono/mono/eventpipe/test/ep-thread-tests.c +++ b/src/mono/mono/eventpipe/test/ep-thread-tests.c @@ -399,7 +399,8 @@ test_thread_session_state (void) provider_config, 1, NULL, - NULL); + NULL, + 0); EP_LOCK_EXIT (section1) if (!session) { diff --git a/src/native/containers/dn-umap-t.h b/src/native/containers/dn-umap-t.h index 9c22938db219bd..50583e947a4ac8 100644 --- a/src/native/containers/dn-umap-t.h +++ b/src/native/containers/dn-umap-t.h @@ -72,5 +72,6 @@ DN_UMAP_T (ptr, void *, int16, int16_t) DN_UMAP_T (ptr, void *, uint16, uint16_t) DN_UMAP_T (ptr, void *, int32, int32_t) DN_UMAP_T (ptr, void *, uint32, uint32_t) +DN_UMAP_T (uint32, uint32_t, ptr, void *) #endif /* __DN_UMAP_T_H__ */ diff --git a/src/native/containers/dn-vector.c b/src/native/containers/dn-vector.c index a70eda7bdb901b..5e2cd46c1e822c 100644 --- a/src/native/containers/dn-vector.c +++ b/src/native/containers/dn-vector.c @@ -268,6 +268,9 @@ dn_vector_custom_free ( dn_vector_t *vector, dn_vector_dispose_func_t dispose_func) { + if (DN_UNLIKELY(!vector)) + return; + dn_vector_custom_dispose (vector, dispose_func); dn_allocator_free (vector->_internal._allocator, vector); } diff --git a/src/native/eventpipe/configure.cmake b/src/native/eventpipe/configure.cmake index b0af4301d6a914..8bb378efd3f20d 100644 --- a/src/native/eventpipe/configure.cmake +++ b/src/native/eventpipe/configure.cmake @@ -1,5 +1,6 @@ include(CheckSymbolExists) include(CheckIncludeFile) +include(CheckIncludeFiles) check_include_file( sys/socket.h @@ -17,6 +18,31 @@ if (CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_ANDROID) set(FEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT 1) endif() +check_include_file( + linux/user_events.h + HAVE_LINUX_USER_EVENTS_H +) + +check_include_file( + sys/ioctl.h + HAVE_SYS_IOCTL_H +) + +check_include_file( + unistd.h + HAVE_UNISTD_H +) + +check_include_file( + "sys/uio.h" + HAVE_SYS_UIO_H +) + +check_include_file( + errno.h + HAVE_ERRNO_H +) + if (NOT DEFINED EP_GENERATED_HEADER_PATH) message(FATAL_ERROR "Required configuration EP_GENERATED_HEADER_PATH not set.") endif (NOT DEFINED EP_GENERATED_HEADER_PATH) diff --git a/src/native/eventpipe/ds-eventpipe-protocol.c b/src/native/eventpipe/ds-eventpipe-protocol.c index b359102ee0d35a..4f5e6daf299d5a 100644 --- a/src/native/eventpipe/ds-eventpipe-protocol.c +++ b/src/native/eventpipe/ds-eventpipe-protocol.c @@ -25,6 +25,14 @@ eventpipe_protocol_helper_send_start_tracing_success ( DiagnosticsIpcStream *stream, EventPipeSessionID session_id); +static +inline +bool +eventpipe_collect_tracing_command_try_parse_session_type ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeSessionType *session_type); + static bool eventpipe_collect_tracing_command_try_parse_serialization_format ( @@ -62,11 +70,62 @@ eventpipe_collect_tracing_command_try_parse_stackwalk_requested ( static bool -eventpipe_collect_tracing_command_try_parse_config ( +eventpipe_collect_tracing_command_try_parse_logging_level ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeEventLevel *logging_level); + +static +bool +eventpipe_collect_tracing_command_try_parse_event_ids ( + uint8_t **buffer, + uint32_t *buffer_len, + uint32_t event_ids_len, + uint32_t **event_ids); + +static +bool +eventpipe_collect_tracing_command_try_parse_event_filter ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeProviderEventFilter **event_filter); + +static +bool +eventpipe_collect_tracing_command_try_parse_tracepoint_sets ( + uint8_t **buffer, + uint32_t *buffer_len, + uint32_t tracepoint_sets_len, + EventPipeProviderTracepointSet **tracepoint_sets); + +static +bool +eventpipe_collect_tracing_command_try_parse_tracepoint_config ( uint8_t **buffer, uint32_t *buffer_len, + EventPipeProviderTracepointConfiguration **tracepoint_config); + +static +bool +eventpipe_collect_tracing_command_try_parse_provider_config ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeProviderOptionalFieldFlags optional_field_flags, + EventPipeProviderConfiguration *provider_config); + +static +bool +eventpipe_collect_tracing_command_try_parse_provider_configs ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeProviderOptionalFieldFlags optional_field_flags, dn_vector_t **result); +static +void +DN_CALLBACK_CALLTYPE +eventpipe_provider_configs_free_func (void *data); + static uint8_t * eventpipe_collect_tracing_command_try_parse_payload ( @@ -91,6 +150,12 @@ eventpipe_collect_tracing4_command_try_parse_payload ( uint8_t *buffer, uint16_t buffer_len); +static +uint8_t * +eventpipe_collect_tracing5_command_try_parse_payload ( + uint8_t *buffer, + uint16_t buffer_len); + static bool eventpipe_protocol_helper_stop_tracing ( @@ -113,6 +178,38 @@ eventpipe_protocol_helper_unknown_command ( * EventPipeCollectTracingCommandPayload */ +static +inline +bool +eventpipe_collect_tracing_command_try_parse_session_type ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeSessionType *type) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (type != NULL); + + uint32_t session_type; + bool can_parse = ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &session_type); + + bool ipc_valid_session_type = false; + switch (session_type) { + case 0: + *type = EP_SESSION_TYPE_IPCSTREAM; + ipc_valid_session_type = true; + break; + case 1: + *type = EP_SESSION_TYPE_USEREVENTS; + ipc_valid_session_type = true; + break; + default: + break; + } + + return can_parse && ipc_valid_session_type; +} + static inline bool @@ -195,78 +292,286 @@ eventpipe_collect_tracing_command_try_parse_stackwalk_requested ( static bool -eventpipe_collect_tracing_command_try_parse_config ( +eventpipe_collect_tracing_command_try_parse_logging_level ( uint8_t **buffer, uint32_t *buffer_len, - dn_vector_t **result) + EventPipeEventLevel *logging_level) { EP_ASSERT (buffer != NULL); EP_ASSERT (buffer_len != NULL); - EP_ASSERT (result != NULL); + EP_ASSERT (logging_level != NULL); - // Picking an arbitrary upper bound, - // This should be larger than any reasonable client request. - // TODO: This might be too large. - const uint32_t max_count_configs = 1000; - uint32_t count_configs = 0; + uint32_t log_level = 0; + bool can_parse = ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &log_level); - uint8_t *provider_name_byte_array = NULL; - uint8_t *filter_data_byte_array = NULL; + *logging_level = (EventPipeEventLevel)log_level; + return can_parse && (0 <= (int32_t)log_level) && ((int32_t)log_level <= (int32_t)EP_EVENT_LEVEL_VERBOSE); +} - ep_char8_t *provider_name_utf8 = NULL; - ep_char8_t *filter_data_utf8 = NULL; +/* + * eventpipe_collect_tracing_command_try_parse_event_ids + * + * Parses an array of event IDs from the IPC buffer. Allocates memory for the array + * and transfers ownership to the caller. + */ +static +bool +eventpipe_collect_tracing_command_try_parse_event_ids ( + uint8_t **buffer, + uint32_t *buffer_len, + uint32_t event_ids_len, + uint32_t **event_ids) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (event_ids != NULL); - dn_vector_custom_alloc_params_t params = {0, }; + bool result = false; + *event_ids = NULL; - ep_raise_error_if_nok (ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &count_configs)); - ep_raise_error_if_nok (count_configs <= max_count_configs); + if (event_ids_len == 0) + return true; - params.capacity = count_configs; + *event_ids = ep_rt_object_array_alloc (uint32_t, event_ids_len); + ep_raise_error_if_nok (*event_ids != NULL); + for (uint32_t i = 0; i < event_ids_len; ++i) + ep_raise_error_if_nok (ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &(*event_ids)[i])); - *result = dn_vector_custom_alloc_t (¶ms, EventPipeProviderConfiguration); - ep_raise_error_if_nok (*result); + result = true; - for (uint32_t i = 0; i < count_configs; ++i) { - uint64_t keywords = 0; - ep_raise_error_if_nok (ds_ipc_message_try_parse_uint64_t (buffer, buffer_len, &keywords)); +ep_on_exit: + return result; + +ep_on_error: + ep_rt_object_array_free (*event_ids); + *event_ids = NULL; + ep_exit_error_handler (); +} + +/* + * eventpipe_collect_tracing_command_try_parse_event_filter + * + * Parses an EventPipeProviderEventFilter from the IPC Stream. Allocates memory for the EventPipeProviderEventFilter + * and transfers ownership to the caller. + */ +static +bool +eventpipe_collect_tracing_command_try_parse_event_filter ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeProviderEventFilter **event_filter) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (event_filter != NULL); - uint32_t log_level = 0; - ep_raise_error_if_nok (ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &log_level)); - ep_raise_error_if_nok (log_level <= EP_EVENT_LEVEL_VERBOSE); + bool result = false; - uint32_t provider_name_byte_array_len = 0; - ep_raise_error_if_nok (ds_ipc_message_try_parse_string_utf16_t_byte_array_alloc (buffer, buffer_len, &provider_name_byte_array, &provider_name_byte_array_len)); + *event_filter = ep_rt_object_alloc (EventPipeProviderEventFilter); + ep_raise_error_if_nok (*event_filter != NULL); - provider_name_utf8 = ep_rt_utf16le_to_utf8_string ((const ep_char16_t *)provider_name_byte_array); - ep_raise_error_if_nok (provider_name_utf8 != NULL); + ep_raise_error_if_nok (ds_ipc_message_try_parse_bool (buffer, buffer_len, &(*event_filter)->enable)); - ep_raise_error_if_nok (!ep_rt_utf8_string_is_null_or_empty (provider_name_utf8)); + ep_raise_error_if_nok (ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &(*event_filter)->length)); - ep_rt_byte_array_free (provider_name_byte_array); - provider_name_byte_array = NULL; + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_event_ids (buffer, buffer_len, (*event_filter)->length, &(*event_filter)->event_ids)); - uint32_t filter_data_byte_array_len = 0; - ep_raise_error_if_nok (ds_ipc_message_try_parse_string_utf16_t_byte_array_alloc (buffer, buffer_len, &filter_data_byte_array, &filter_data_byte_array_len)); + result = true; - // This parameter is optional. - if (filter_data_byte_array) { - filter_data_utf8 = ep_rt_utf16le_to_utf8_string ((const ep_char16_t *)filter_data_byte_array); - ep_raise_error_if_nok (filter_data_utf8 != NULL); +ep_on_exit: + return result; - ep_rt_byte_array_free (filter_data_byte_array); - filter_data_byte_array = NULL; - } +ep_on_error: + eventpipe_collect_tracing_command_free_event_filter (*event_filter); + *event_filter = NULL; + ep_exit_error_handler (); +} + +/* + * eventpipe_collect_tracing_command_try_parse_tracepoint_sets + * + * Parses an array of EventPipeProviderTracepointSets from the IPC buffer. + * Allocates memory for the array and its contents, passing ownership to the caller. + */ +static +bool +eventpipe_collect_tracing_command_try_parse_tracepoint_sets ( + uint8_t **buffer, + uint32_t *buffer_len, + uint32_t tracepoint_sets_len, + EventPipeProviderTracepointSet **tracepoint_sets) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (tracepoint_sets != NULL); + + bool result = false; + *tracepoint_sets = NULL; + + if (tracepoint_sets_len == 0) + return false; + + *tracepoint_sets = ep_rt_object_array_alloc (EventPipeProviderTracepointSet, tracepoint_sets_len); + ep_raise_error_if_nok (*tracepoint_sets != NULL); + + for (uint32_t i = 0; i < tracepoint_sets_len; ++i) { + ep_raise_error_if_nok (ds_ipc_message_try_parse_string_utf16_t_string_utf8_t_alloc (buffer, buffer_len, &(*tracepoint_sets)[i].tracepoint_name)); + ep_raise_error_if_nok (!ep_rt_utf8_string_is_null_or_empty ((*tracepoint_sets)[i].tracepoint_name)); + + ep_raise_error_if_nok (ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &(*tracepoint_sets)[i].event_ids_length)); + + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_event_ids (buffer, buffer_len, (*tracepoint_sets)[i].event_ids_length, &(*tracepoint_sets)[i].event_ids)); + } + + result = true; + +ep_on_exit: + return result; + +ep_on_error: + eventpipe_collect_tracing_command_free_tracepoint_sets (*tracepoint_sets, tracepoint_sets_len); + *tracepoint_sets = NULL; + ep_exit_error_handler (); +} + +/* + * eventpipe_collect_tracing_command_try_parse_tracepoint_config + * + * Parses an EventPipeProviderTracepointConfiguration from the IPC Stream. + * Allocates memory for the EventPipeProviderTracepointConfiguration and its fields, + * passing ownership to the caller. + */ +static +bool +eventpipe_collect_tracing_command_try_parse_tracepoint_config ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeProviderTracepointConfiguration **tracepoint_config) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (tracepoint_config != NULL); + + bool result = false; + *tracepoint_config = ep_rt_object_alloc (EventPipeProviderTracepointConfiguration); + ep_raise_error_if_nok (*tracepoint_config != NULL); + + ep_raise_error_if_nok (ds_ipc_message_try_parse_string_utf16_t_string_utf8_t_alloc (buffer, buffer_len, &(*tracepoint_config)->default_tracepoint_name)); + + ep_raise_error_if_nok (ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &(*tracepoint_config)->non_default_tracepoints_length)); + + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_tracepoint_sets (buffer, buffer_len, (*tracepoint_config)->non_default_tracepoints_length, &(*tracepoint_config)->non_default_tracepoints)); + + ep_raise_error_if_nok ((*tracepoint_config)->default_tracepoint_name != NULL || (*tracepoint_config)->non_default_tracepoints_length > 0); + + result = true; + +ep_on_exit: + return result; + +ep_on_error: + eventpipe_collect_tracing_command_free_tracepoint_config (*tracepoint_config); + *tracepoint_config = NULL; + ep_exit_error_handler (); +} + +/* + * eventpipe_collect_tracing_command_try_parse_provider_config + * + * Deserializes a single EventPipeProviderConfiguration from the IPC Stream + * + * Dynamically allocates memory for the EventPipeProviderConfiguration fields and passes ownership to the caller. + */ +static +bool +eventpipe_collect_tracing_command_try_parse_provider_config ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeProviderOptionalFieldFlags optional_field_flags, + EventPipeProviderConfiguration *provider_config) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (provider_config != NULL); + + bool result = false; + + provider_config->keywords = 0; + provider_config->logging_level = (EventPipeEventLevel)0; + provider_config->provider_name = NULL; + provider_config->filter_data = NULL; + provider_config->event_filter = NULL; + provider_config->tracepoint_config = NULL; + + ep_raise_error_if_nok (ds_ipc_message_try_parse_uint64_t (buffer, buffer_len, &provider_config->keywords)); + + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_logging_level (buffer, buffer_len, &provider_config->logging_level)); + + ep_raise_error_if_nok (ds_ipc_message_try_parse_string_utf16_t_string_utf8_t_alloc (buffer, buffer_len, &provider_config->provider_name)); + ep_raise_error_if_nok (!ep_rt_utf8_string_is_null_or_empty (provider_config->provider_name)); + + ep_raise_error_if_nok (ds_ipc_message_try_parse_string_utf16_t_string_utf8_t_alloc (buffer, buffer_len, &provider_config->filter_data)); + + if ((optional_field_flags & EP_PROVIDER_OPTFIELD_EVENT_FILTER) != 0) + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_event_filter (buffer, buffer_len, &provider_config->event_filter)); + + if ((optional_field_flags & EP_PROVIDER_OPTFIELD_TRACEPOINT_CONFIG) != 0) + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_tracepoint_config (buffer, buffer_len, &provider_config->tracepoint_config)); + + result = true; + +ep_on_exit: + return result; + +ep_on_error: + ep_provider_config_fini (provider_config); + ep_exit_error_handler (); +} + +/* + * eventpipe_collect_tracing_command_try_parse_provider_configs + * + * With the introduction of CollectTracing5, there is more flexiblity in provider configuration encoding. + * This function deserializes all provider configurations from the IPC Stream, providing callers the flexibility + * to specify which optional fields are present for the particular CollectTracingN command. + * + * Ownership of all EventPipeProviderConfigurations data is transferred to the caller. + */ +static +bool +eventpipe_collect_tracing_command_try_parse_provider_configs ( + uint8_t **buffer, + uint32_t *buffer_len, + EventPipeProviderOptionalFieldFlags optional_field_flags, + dn_vector_t **result) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (result != NULL); + + // Picking an arbitrary upper bound, + // This should be larger than any reasonable client request. + const uint32_t max_count_configs = 1000; + uint32_t count_configs = 0; + dn_vector_custom_alloc_params_t params = {0, }; + + ep_raise_error_if_nok (ds_ipc_message_try_parse_uint32_t (buffer, buffer_len, &count_configs)); + ep_raise_error_if_nok (count_configs <= max_count_configs); + params.capacity = count_configs; + *result = dn_vector_custom_alloc_t (¶ms, EventPipeProviderConfiguration); + ep_raise_error_if_nok (*result); + + for (uint32_t i = 0; i < count_configs; ++i) { EventPipeProviderConfiguration provider_config; - if (ep_provider_config_init (&provider_config, provider_name_utf8, keywords, (EventPipeEventLevel)log_level, filter_data_utf8)) { - if (dn_vector_push_back (*result, provider_config)) { - // Ownership transferred. - provider_name_utf8 = NULL; - filter_data_utf8 = NULL; - } + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_provider_config ( + buffer, + buffer_len, + optional_field_flags, + &provider_config)); + + if (!dn_vector_push_back (*result, provider_config)) ep_provider_config_fini (&provider_config); - } - ep_raise_error_if_nok (provider_name_utf8 == NULL && filter_data_utf8 == NULL); } ep_on_exit: @@ -274,10 +579,8 @@ eventpipe_collect_tracing_command_try_parse_config ( ep_on_error: count_configs = 0; - ep_rt_byte_array_free (provider_name_byte_array); - ep_rt_utf8_string_free (provider_name_utf8); - ep_rt_byte_array_free (filter_data_byte_array); - ep_rt_utf8_string_free (filter_data_utf8); + dn_vector_custom_free (*result, eventpipe_provider_configs_free_func); + *result = NULL; ep_exit_error_handler (); } @@ -287,16 +590,21 @@ ds_eventpipe_collect_tracing_command_payload_alloc (void) return ep_rt_object_alloc (EventPipeCollectTracingCommandPayload); } +static +void +DN_CALLBACK_CALLTYPE +eventpipe_provider_configs_free_func (void *data) +{ + ep_provider_config_fini ((EventPipeProviderConfiguration *)data); +} + void ds_eventpipe_collect_tracing_command_payload_free (EventPipeCollectTracingCommandPayload *payload) { ep_return_void_if_nok (payload != NULL); ep_rt_byte_array_free (payload->incoming_buffer); - DN_VECTOR_FOREACH_BEGIN (EventPipeProviderConfiguration, config, payload->provider_configs) { - ep_rt_utf8_string_free ((ep_char8_t *)ep_provider_config_get_provider_name (&config)); - ep_rt_utf8_string_free ((ep_char8_t *)ep_provider_config_get_filter_data (&config)); - } DN_VECTOR_FOREACH_END; + dn_vector_custom_free (payload->provider_configs, eventpipe_provider_configs_free_func); ep_rt_object_free (payload); } @@ -323,11 +631,12 @@ eventpipe_collect_tracing_command_try_parse_payload ( if (!eventpipe_collect_tracing_command_try_parse_circular_buffer_size (&buffer_cursor, &buffer_cursor_len, &instance->circular_buffer_size_in_mb ) || !eventpipe_collect_tracing_command_try_parse_serialization_format (&buffer_cursor, &buffer_cursor_len, &instance->serialization_format) || - !eventpipe_collect_tracing_command_try_parse_config (&buffer_cursor, &buffer_cursor_len, &instance->provider_configs)) + !eventpipe_collect_tracing_command_try_parse_provider_configs (&buffer_cursor, &buffer_cursor_len, EP_PROVIDER_OPTFIELD_NONE, &instance->provider_configs)) ep_raise_error (); instance->rundown_requested = true; instance->stackwalk_requested = true; instance->rundown_keyword = ep_default_rundown_keyword; + instance->session_type = EP_SESSION_TYPE_IPCSTREAM; ep_on_exit: return (uint8_t *)instance; @@ -357,12 +666,13 @@ eventpipe_collect_tracing2_command_try_parse_payload ( if (!eventpipe_collect_tracing_command_try_parse_circular_buffer_size (&buffer_cursor, &buffer_cursor_len, &instance->circular_buffer_size_in_mb ) || !eventpipe_collect_tracing_command_try_parse_serialization_format (&buffer_cursor, &buffer_cursor_len, &instance->serialization_format) || !eventpipe_collect_tracing_command_try_parse_rundown_requested (&buffer_cursor, &buffer_cursor_len, &instance->rundown_requested) || - !eventpipe_collect_tracing_command_try_parse_config (&buffer_cursor, &buffer_cursor_len, &instance->provider_configs)) + !eventpipe_collect_tracing_command_try_parse_provider_configs (&buffer_cursor, &buffer_cursor_len, EP_PROVIDER_OPTFIELD_NONE, &instance->provider_configs)) ep_raise_error (); instance->rundown_keyword = instance->rundown_requested ? ep_default_rundown_keyword : 0; instance->stackwalk_requested = true; + instance->session_type = EP_SESSION_TYPE_IPCSTREAM; ep_on_exit: return (uint8_t *)instance; @@ -393,10 +703,11 @@ eventpipe_collect_tracing3_command_try_parse_payload ( !eventpipe_collect_tracing_command_try_parse_serialization_format (&buffer_cursor, &buffer_cursor_len, &instance->serialization_format) || !eventpipe_collect_tracing_command_try_parse_rundown_requested (&buffer_cursor, &buffer_cursor_len, &instance->rundown_requested) || !eventpipe_collect_tracing_command_try_parse_stackwalk_requested (&buffer_cursor, &buffer_cursor_len, &instance->stackwalk_requested) || - !eventpipe_collect_tracing_command_try_parse_config (&buffer_cursor, &buffer_cursor_len, &instance->provider_configs)) + !eventpipe_collect_tracing_command_try_parse_provider_configs (&buffer_cursor, &buffer_cursor_len, EP_PROVIDER_OPTFIELD_NONE, &instance->provider_configs)) ep_raise_error (); instance->rundown_keyword = instance->rundown_requested ? ep_default_rundown_keyword : 0; + instance->session_type = EP_SESSION_TYPE_IPCSTREAM; ep_on_exit: return (uint8_t *)instance; @@ -427,10 +738,70 @@ eventpipe_collect_tracing4_command_try_parse_payload ( !eventpipe_collect_tracing_command_try_parse_serialization_format (&buffer_cursor, &buffer_cursor_len, &instance->serialization_format) || !eventpipe_collect_tracing_command_try_parse_rundown_keyword (&buffer_cursor, &buffer_cursor_len, &instance->rundown_keyword) || !eventpipe_collect_tracing_command_try_parse_stackwalk_requested (&buffer_cursor, &buffer_cursor_len, &instance->stackwalk_requested) || - !eventpipe_collect_tracing_command_try_parse_config (&buffer_cursor, &buffer_cursor_len, &instance->provider_configs)) + !eventpipe_collect_tracing_command_try_parse_provider_configs (&buffer_cursor, &buffer_cursor_len, EP_PROVIDER_OPTFIELD_NONE, &instance->provider_configs)) ep_raise_error (); instance->rundown_requested = instance->rundown_keyword != 0; + instance->session_type = EP_SESSION_TYPE_IPCSTREAM; + +ep_on_exit: + return (uint8_t *)instance; + +ep_on_error: + ds_eventpipe_collect_tracing_command_payload_free (instance); + instance = NULL; + ep_exit_error_handler (); +} + +/* + * eventpipe_collect_tracing5_command_try_parse_payload + * + * Implements the CollectTracing5 IPC Protocol deserialization. + * + * Ownership of the EventPipeCollectTracingCommandPayload is transferred to the caller. + */ +static +uint8_t * +eventpipe_collect_tracing5_command_try_parse_payload ( + uint8_t *buffer, + uint16_t buffer_len) +{ + EP_ASSERT (buffer != NULL); + + uint8_t * buffer_cursor = buffer; + uint32_t buffer_cursor_len = buffer_len; + + EventPipeProviderOptionalFieldFlags optional_field_flags = EP_PROVIDER_OPTFIELD_EVENT_FILTER; + + EventPipeCollectTracingCommandPayload *instance = ds_eventpipe_collect_tracing_command_payload_alloc (); + ep_raise_error_if_nok (instance != NULL); + + instance->incoming_buffer = buffer; + + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_session_type (&buffer_cursor, &buffer_cursor_len, &instance->session_type)); + + if (instance->session_type == EP_SESSION_TYPE_IPCSTREAM) { + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_circular_buffer_size (&buffer_cursor, &buffer_cursor_len, &instance->circular_buffer_size_in_mb)); + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_serialization_format (&buffer_cursor, &buffer_cursor_len, &instance->serialization_format)); + } else if (instance->session_type == EP_SESSION_TYPE_USEREVENTS) { + instance->circular_buffer_size_in_mb = 0; + instance->serialization_format = EP_SERIALIZATION_FORMAT_NETTRACE_V4; // Serialization format isn't used for user_events sessions, default for check_options_valid. + } + + ep_raise_error_if_nok (ds_ipc_message_try_parse_uint64_t (&buffer_cursor, &buffer_cursor_len, &instance->rundown_keyword)); + + if (instance->session_type == EP_SESSION_TYPE_IPCSTREAM) { + ep_raise_error_if_nok (ds_ipc_message_try_parse_bool (&buffer_cursor, &buffer_cursor_len, &instance->stackwalk_requested)); + } else if (instance->session_type == EP_SESSION_TYPE_USEREVENTS) { + instance->stackwalk_requested = false; + } + + if (instance->session_type == EP_SESSION_TYPE_USEREVENTS) + optional_field_flags = (EventPipeProviderOptionalFieldFlags)(optional_field_flags | EP_PROVIDER_OPTFIELD_TRACEPOINT_CONFIG); + + ep_raise_error_if_nok (eventpipe_collect_tracing_command_try_parse_provider_configs (&buffer_cursor, &buffer_cursor_len, optional_field_flags, &instance->provider_configs)); + + instance->rundown_requested = instance->rundown_keyword != 0; ep_on_exit: return (uint8_t *)instance; @@ -530,6 +901,14 @@ eventpipe_protocol_helper_collect_tracing ( return false; } + int user_events_data_fd = -1; + if (payload->session_type == EP_SESSION_TYPE_USEREVENTS) { + if (!ds_ipc_stream_read_fd (stream, &user_events_data_fd)) { + ds_ipc_message_send_error (stream, DS_IPC_E_BAD_ENCODING); + return false; + } + } + EventPipeSessionOptions options; ep_session_options_init( &options, @@ -537,17 +916,18 @@ eventpipe_protocol_helper_collect_tracing ( payload->circular_buffer_size_in_mb, dn_vector_data_t (payload->provider_configs, EventPipeProviderConfiguration), dn_vector_size (payload->provider_configs), - EP_SESSION_TYPE_IPCSTREAM, + payload->session_type, payload->serialization_format, payload->rundown_keyword, payload->stackwalk_requested, - ds_ipc_stream_get_stream_ref (stream), + payload->session_type == EP_SESSION_TYPE_IPCSTREAM ? ds_ipc_stream_get_stream_ref (stream) : NULL, + NULL, NULL, - NULL); + user_events_data_fd); EventPipeSessionID session_id = 0; bool result = false; - session_id = ep_enable_3(&options); + session_id = ep_enable_3 (&options); if (session_id == 0) { ds_ipc_message_send_error (stream, DS_IPC_E_FAIL); @@ -616,6 +996,10 @@ ds_eventpipe_protocol_helper_handle_ipc_message ( payload = (EventPipeCollectTracingCommandPayload *)ds_ipc_message_try_parse_payload (message, eventpipe_collect_tracing4_command_try_parse_payload); result = eventpipe_protocol_helper_collect_tracing (payload, stream); break; + case EP_COMMANDID_COLLECT_TRACING_5: + payload = (EventPipeCollectTracingCommandPayload *)ds_ipc_message_try_parse_payload (message, eventpipe_collect_tracing5_command_try_parse_payload); + result = eventpipe_protocol_helper_collect_tracing (payload, stream); + break; case EP_COMMANDID_STOP_TRACING: result = eventpipe_protocol_helper_stop_tracing (message, stream); break; diff --git a/src/native/eventpipe/ds-eventpipe-protocol.h b/src/native/eventpipe/ds-eventpipe-protocol.h index 14496068a109b9..749a44e1a9edc6 100644 --- a/src/native/eventpipe/ds-eventpipe-protocol.h +++ b/src/native/eventpipe/ds-eventpipe-protocol.h @@ -13,28 +13,35 @@ #endif #include "ds-getter-setter.h" +/* + * CollectTracing5 introduces additional provider configuration fields. + * For backwards compatibility, these fields are optional and + * these flags indicate which of the optional fields should be + * deserialized from the IPC Stream. + */ +typedef enum +{ + EP_PROVIDER_OPTFIELD_NONE = 0, + EP_PROVIDER_OPTFIELD_EVENT_FILTER = 1, + EP_PROVIDER_OPTFIELD_TRACEPOINT_CONFIG = 2 +} EventPipeProviderOptionalFieldFlags; + /* * EventPipeCollectTracingCommandPayload +* +* https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md */ // Command = 0x0202 // Command = 0x0203 // Command = 0x0204 // Command = 0x0205 +// Command = 0x0206 #if defined(DS_INLINE_GETTER_SETTER) || defined(DS_IMPL_EVENTPIPE_PROTOCOL_GETTER_SETTER) struct _EventPipeCollectTracingCommandPayload { #else struct _EventPipeCollectTracingCommandPayload_Internal { #endif - // The protocol buffer is defined as: - // X, Y, Z means encode bytes for X followed by bytes for Y followed by bytes for Z - // message = uint circularBufferMB, uint format, array providers - // uint = 4 little endian bytes - // wchar = 2 little endian bytes, UTF16 encoding - // array = uint length, length # of Ts - // string = (array where the last char must = 0) or (length = 0) - // provider_config = ulong keywords, uint logLevel, string provider_name, string filter_data - uint8_t *incoming_buffer; dn_vector_t *provider_configs; uint32_t circular_buffer_size_in_mb; @@ -42,6 +49,7 @@ struct _EventPipeCollectTracingCommandPayload_Internal { bool rundown_requested; bool stackwalk_requested; uint64_t rundown_keyword; + EventPipeSessionType session_type; }; #if !defined(DS_INLINE_GETTER_SETTER) && !defined(DS_IMPL_EVENTPIPE_PROTOCOL_GETTER_SETTER) diff --git a/src/native/eventpipe/ds-ipc-pal-namedpipe.c b/src/native/eventpipe/ds-ipc-pal-namedpipe.c index b7cfd0528fa4e0..2444cb763c6496 100644 --- a/src/native/eventpipe/ds-ipc-pal-namedpipe.c +++ b/src/native/eventpipe/ds-ipc-pal-namedpipe.c @@ -906,6 +906,15 @@ ds_ipc_stream_read ( timeout_ms); } +bool +ds_ipc_stream_read_fd ( + DiagnosticsIpcStream *ipc_stream, + int *data_fd) +{ + // Not Supported + return false; +} + bool ds_ipc_stream_write ( DiagnosticsIpcStream *ipc_stream, diff --git a/src/native/eventpipe/ds-ipc-pal-socket.c b/src/native/eventpipe/ds-ipc-pal-socket.c index c9764e6a3ffd6a..4a16fb5f81f253 100644 --- a/src/native/eventpipe/ds-ipc-pal-socket.c +++ b/src/native/eventpipe/ds-ipc-pal-socket.c @@ -552,9 +552,9 @@ ipc_socket_accept ( DS_ENTER_BLOCKING_PAL_SECTION; do { #if HAVE_ACCEPT4 && defined(SOCK_CLOEXEC) - client_socket = accept4 (s, address, address_len, SOCK_CLOEXEC); + client_socket = accept4 (s, address, address_len, SOCK_CLOEXEC); #else - client_socket = accept (s, address, address_len); + client_socket = accept (s, address, address_len); #endif } while (ipc_retry_syscall (client_socket)); @@ -1556,6 +1556,60 @@ ds_ipc_stream_read ( timeout_ms); } +#if HAVE_SYS_SOCKET_H && defined(SOL_SOCKET) && defined(SCM_RIGHTS) && defined(CMSG_SPACE) && defined(CMSG_FIRSTHDR) && defined(CMSG_DATA) +bool +ds_ipc_stream_read_fd ( + DiagnosticsIpcStream *ipc_stream, + int *data_fd) +{ + EP_ASSERT (ipc_stream != NULL); + EP_ASSERT (data_fd != NULL); + + struct msghdr msg = {0}; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + struct iovec io_vec[1]; + char buffer[1]; + io_vec[0].iov_base = buffer; + io_vec[0].iov_len = 1; + + msg.msg_iov = io_vec; + msg.msg_iovlen = 1; + + char control[CMSG_SPACE(sizeof(int))]; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + ssize_t res; + while ((res = recvmsg(ipc_stream->client_socket, &msg, 0)) < 0 && errno == EINTR); + if (res < 0) + return false; + + struct cmsghdr *cmptr; + if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL || + cmptr->cmsg_level != SOL_SOCKET || + cmptr->cmsg_type != SCM_RIGHTS) + return false; + + memcpy(data_fd, CMSG_DATA(cmptr), sizeof(int)); + if (*data_fd < 0) + return false; + + return true; +} +#else // HAVE_SYS_SOCKET_H && defined(SOL_SOCKET) && defined(SCM_RIGHTS) && defined(CMSG_SPACE) && defined(CMSG_FIRSTHDR) && defined(CMSG_DATA) +bool +ds_ipc_stream_read_fd ( + DiagnosticsIpcStream *ipc_stream, + int *data_fd) +{ + // Not supported + return false; +} +#endif // HAVE_SYS_SOCKET_H && defined(SOL_SOCKET) && defined(SCM_RIGHTS) && defined(CMSG_SPACE) && defined(CMSG_FIRSTHDR) && defined(CMSG_DATA) + bool ds_ipc_stream_write ( DiagnosticsIpcStream *ipc_stream, diff --git a/src/native/eventpipe/ds-ipc-pal-websocket.c b/src/native/eventpipe/ds-ipc-pal-websocket.c index 21f617325d9a12..97eb89025a468a 100644 --- a/src/native/eventpipe/ds-ipc-pal-websocket.c +++ b/src/native/eventpipe/ds-ipc-pal-websocket.c @@ -490,6 +490,15 @@ ds_ipc_stream_read ( timeout_ms); } +bool +ds_ipc_stream_read_fd ( + DiagnosticsIpcStream *ipc_stream, + int *data_fd) +{ + // Not Supported + return false; +} + bool ds_ipc_stream_write ( DiagnosticsIpcStream *ipc_stream, diff --git a/src/native/eventpipe/ds-ipc-pal.h b/src/native/eventpipe/ds-ipc-pal.h index 8e246ed671955c..362ea3925f92ba 100644 --- a/src/native/eventpipe/ds-ipc-pal.h +++ b/src/native/eventpipe/ds-ipc-pal.h @@ -113,6 +113,11 @@ ds_ipc_stream_read ( uint32_t *bytes_read, uint32_t timeout_ms); +bool +ds_ipc_stream_read_fd ( + DiagnosticsIpcStream *ipc_stream, + int *data_fd); + bool ds_ipc_stream_write ( DiagnosticsIpcStream *ipc_stream, diff --git a/src/native/eventpipe/ds-ipc.c b/src/native/eventpipe/ds-ipc.c index f8cd6a5ad52ee3..6527d5bbce706d 100644 --- a/src/native/eventpipe/ds-ipc.c +++ b/src/native/eventpipe/ds-ipc.c @@ -709,7 +709,7 @@ connect_port_get_ipc_poll_handle_func ( buffer [0] = '\0'; DS_LOG_DEBUG_1 ("connect_port_get_ipc_poll_handle - returned connection %s", buffer); - if (!ds_icp_advertise_v1_send (connection)) { + if (!ds_ipc_advertise_v1_send (connection)) { if (callback) callback("Failed to send advertise message", -1); ep_raise_error (); diff --git a/src/native/eventpipe/ds-protocol.c b/src/native/eventpipe/ds-protocol.c index d1cbee0ac35782..8338c8103a9550 100644 --- a/src/native/eventpipe/ds-protocol.c +++ b/src/native/eventpipe/ds-protocol.c @@ -26,7 +26,7 @@ const DiagnosticsIpcHeader _ds_ipc_generic_error_header = { (uint16_t)0x0000 }; -static uint8_t _ds_ipc_advertise_cooike_v1 [EP_GUID_SIZE] = { 0 }; +static uint8_t _ds_ipc_advertise_cookie_v1 [EP_GUID_SIZE] = { 0 }; /* * Forward declares of all static functions. @@ -74,13 +74,13 @@ ipc_message_try_parse_string_utf16_t_byte_array ( uint8_t * ds_ipc_advertise_cookie_v1_get (void) { - return _ds_ipc_advertise_cooike_v1; + return _ds_ipc_advertise_cookie_v1; } void ds_ipc_advertise_cookie_v1_init (void) { - ep_thread_create_activity_id ((uint8_t *)&_ds_ipc_advertise_cooike_v1, EP_GUID_SIZE); + ep_thread_create_activity_id ((uint8_t *)&_ds_ipc_advertise_cookie_v1, EP_GUID_SIZE); } /** @@ -98,7 +98,7 @@ ds_ipc_advertise_cookie_v1_init (void) * 2 bytes - unused 2 byte field for futureproofing */ bool -ds_icp_advertise_v1_send (DiagnosticsIpcStream *stream) +ds_ipc_advertise_v1_send (DiagnosticsIpcStream *stream) { uint8_t advertise_buffer [DOTNET_IPC_V1_ADVERTISE_SIZE]; uint8_t *cookie = ds_ipc_advertise_cookie_v1_get (); @@ -426,15 +426,15 @@ ds_ipc_message_try_parse_bool ( uint32_t *buffer_len, bool *value) { - EP_ASSERT (buffer != NULL); - EP_ASSERT (buffer_len != NULL); - EP_ASSERT (value != NULL); - - uint8_t temp_value; - bool result = ds_ipc_message_try_parse_value (buffer, buffer_len, (uint8_t *)&temp_value, 1); - if (result) - *value = temp_value == 0 ? false : true; - return result; + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (value != NULL); + + uint8_t temp_value; + bool result = ds_ipc_message_try_parse_value (buffer, buffer_len, (uint8_t *)&temp_value, 1); + if (result) + *value = temp_value == 0 ? false : true; + return result; } bool @@ -453,6 +453,45 @@ ds_ipc_message_try_parse_uint32_t ( return result; } +bool +ds_ipc_message_try_parse_string_utf16_t_string_utf8_t_alloc ( + uint8_t **buffer, + uint32_t *buffer_len, + ep_char8_t **string_utf8) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len != NULL); + EP_ASSERT (string_utf8 != NULL); + + bool result = false; + + uint8_t *byte_array = NULL; + uint32_t byte_array_len = 0; + + *string_utf8 = NULL; + + ep_raise_error_if_nok (ds_ipc_message_try_parse_string_utf16_t_byte_array_alloc (buffer, buffer_len, &byte_array, &byte_array_len)); + + if (byte_array) { + *string_utf8 = ep_rt_utf16le_to_utf8_string ((const ep_char16_t *)byte_array); + ep_raise_error_if_nok (*string_utf8 != NULL); + + ep_rt_byte_array_free (byte_array); + byte_array = NULL; + } + + result = true; + +ep_on_exit: + return result; + +ep_on_error: + ep_rt_byte_array_free (byte_array); + ep_rt_utf8_string_free (*string_utf8); + *string_utf8 = NULL; + ep_exit_error_handler (); +} + bool ds_ipc_message_try_parse_string_utf16_t_byte_array_alloc ( uint8_t **buffer, diff --git a/src/native/eventpipe/ds-protocol.h b/src/native/eventpipe/ds-protocol.h index bb3a10120341d6..8205602206df86 100644 --- a/src/native/eventpipe/ds-protocol.h +++ b/src/native/eventpipe/ds-protocol.h @@ -27,7 +27,7 @@ void ds_ipc_advertise_cookie_v1_init (void); bool -ds_icp_advertise_v1_send (DiagnosticsIpcStream *stream); +ds_ipc_advertise_v1_send (DiagnosticsIpcStream *stream); /* * DiagnosticsIpcHeader @@ -59,8 +59,8 @@ struct _DiagnosticsIpcHeader { #endif DS_DEFINE_GETTER_ARRAY_REF(DiagnosticsIpcHeader *, ipc_header, uint8_t *, const uint8_t *, magic, magic[0]) -DS_DEFINE_GETTER(DiagnosticsIpcHeader *, ipc_header, uint8_t, commandset) -DS_DEFINE_GETTER(DiagnosticsIpcHeader *, ipc_header, uint8_t, commandid) +DS_DEFINE_GETTER(DiagnosticsIpcHeader *, ipc_header, uint8_t, commandset) // ds_ipc_header_get_commandset +DS_DEFINE_GETTER(DiagnosticsIpcHeader *, ipc_header, uint8_t, commandid) // ds_ipc_header_get_commandid /* * DiagnosticsIpcMessage @@ -87,7 +87,7 @@ struct _DiagnosticsIpcMessage { }; #endif -DS_DEFINE_GETTER_REF(DiagnosticsIpcMessage *, ipc_message, DiagnosticsIpcHeader *, header) +DS_DEFINE_GETTER_REF(DiagnosticsIpcMessage *, ipc_message, DiagnosticsIpcHeader *, header) // ds_ipc_message_get_header_ref DiagnosticsIpcMessage * ds_ipc_message_init (DiagnosticsIpcMessage *message); @@ -129,6 +129,12 @@ ds_ipc_message_try_parse_uint32_t ( uint32_t *buffer_len, uint32_t *value); +bool +ds_ipc_message_try_parse_string_utf16_t_string_utf8_t_alloc ( + uint8_t **buffer, + uint32_t *buffer_len, + ep_char8_t **string_utf8); + bool ds_ipc_message_try_parse_string_utf16_t_byte_array_alloc ( uint8_t **buffer, diff --git a/src/native/eventpipe/ds-server.c b/src/native/eventpipe/ds-server.c index 52d5da9cd5da2c..a89f757970167c 100644 --- a/src/native/eventpipe/ds-server.c +++ b/src/native/eventpipe/ds-server.c @@ -145,18 +145,18 @@ static size_t server_loop_tick (void* data) { DS_LOG_INFO_2 ("DiagnosticServer - received IPC message with command set (%d) and command id (%d)", ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message)), ds_ipc_header_get_commandid (ds_ipc_message_get_header_ref (&message))); switch ((DiagnosticsServerCommandSet)ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message))) { - case DS_SERVER_COMMANDSET_EVENTPIPE: - ds_eventpipe_protocol_helper_handle_ipc_message (&message, stream); - break; case DS_SERVER_COMMANDSET_DUMP: ds_dump_protocol_helper_handle_ipc_message (&message, stream); break; - case DS_SERVER_COMMANDSET_PROCESS: - ds_process_protocol_helper_handle_ipc_message (&message, stream); + case DS_SERVER_COMMANDSET_EVENTPIPE: + ds_eventpipe_protocol_helper_handle_ipc_message (&message, stream); break; case DS_SERVER_COMMANDSET_PROFILER: ds_profiler_protocol_helper_handle_ipc_message (&message, stream); break; + case DS_SERVER_COMMANDSET_PROCESS: + ds_process_protocol_helper_handle_ipc_message (&message, stream); + break; default: server_protocol_helper_unknown_command (&message, stream); break; diff --git a/src/native/eventpipe/ds-types.h b/src/native/eventpipe/ds-types.h index a7596da6052a33..5337497e180f21 100644 --- a/src/native/eventpipe/ds-types.h +++ b/src/native/eventpipe/ds-types.h @@ -43,15 +43,6 @@ typedef struct _EventPipeStopTracingCommandPayload EventPipeStopTracingCommandPa * Diagnostics Enums. */ -// The Diagnostic command set is 0x01 -typedef enum { - DS_DUMP_COMMANDID_RESERVED = 0x00, - DS_DUMP_COMMANDID_GENERATE_CORE_DUMP = 0x01, - DS_DUMP_COMMANDID_GENERATE_CORE_DUMP2 = 0x02, - DS_DUMP_COMMANDID_GENERATE_CORE_DUMP3 = 0x03, - // future -} DiagnosticsDumpCommandId; - typedef enum { DS_IPC_MAGIC_VERSION_DOTNET_IPC_V1 = 0x01, // FUTURE @@ -66,8 +57,35 @@ typedef enum { DS_SERVER_COMMANDSET_SERVER = 0xFF } DiagnosticsServerCommandSet; +// The dump command set is 0x01 +typedef enum { + DS_DUMP_COMMANDID_RESERVED = 0x00, + DS_DUMP_COMMANDID_GENERATE_CORE_DUMP = 0x01, + DS_DUMP_COMMANDID_GENERATE_CORE_DUMP2 = 0x02, + DS_DUMP_COMMANDID_GENERATE_CORE_DUMP3 = 0x03, + // future +} DiagnosticsDumpCommandId; + // The event pipe command set is 0x02 -// see ds-ipc.h and ds-server.h for more details +typedef enum { + EP_COMMANDID_STOP_TRACING = 0x01, + EP_COMMANDID_COLLECT_TRACING = 0x02, + EP_COMMANDID_COLLECT_TRACING_2 = 0x03, + EP_COMMANDID_COLLECT_TRACING_3 = 0x04, + EP_COMMANDID_COLLECT_TRACING_4 = 0x05, + EP_COMMANDID_COLLECT_TRACING_5 = 0x06, + // future +} EventPipeCommandId; + +// The profiler command set is 0x03 +typedef enum { + DS_PROFILER_COMMANDID_RESERVED = 0x00, + DS_PROFILER_COMMANDID_ATTACH_PROFILER = 0x01, + DS_PROFILER_COMMANDID_STARTUP_PROFILER = 0x02, + // future +} DiagnosticsProfilerCommandId; + +// The process command set is 0x04 typedef enum { DS_PROCESS_COMMANDID_GET_PROCESS_INFO = 0x00, DS_PROCESS_COMMANDID_RESUME_RUNTIME = 0x01, @@ -81,14 +99,6 @@ typedef enum { // future } DiagnosticsProcessCommandId; -// The Diagnostic command set is 0x01 -typedef enum { - DS_PROFILER_COMMANDID_RESERVED = 0x00, - DS_PROFILER_COMMANDID_ATTACH_PROFILER = 0x01, - DS_PROFILER_COMMANDID_STARTUP_PROFILER = 0x02, - // future -} DiagnosticsProfilerCommandId; - // Overlaps with DiagnosticsServerCommandId // DON'T create overlapping values typedef enum { @@ -97,17 +107,6 @@ typedef enum { DS_SERVER_RESPONSEID_ERROR = 0xFF, } DiagnosticsServerResponseId; -// The event pipe command set is 0x02 -// see ds-ipc.h and ds-server.h for more details -typedef enum { - EP_COMMANDID_STOP_TRACING = 0x01, - EP_COMMANDID_COLLECT_TRACING = 0x02, - EP_COMMANDID_COLLECT_TRACING_2 = 0x03, - EP_COMMANDID_COLLECT_TRACING_3 = 0x04, - EP_COMMANDID_COLLECT_TRACING_4 = 0x05, - // future -} EventPipeCommandId; - typedef enum { DS_PORT_TYPE_LISTEN = 0, DS_PORT_TYPE_CONNECT = 1 diff --git a/src/native/eventpipe/ep-event-payload.h b/src/native/eventpipe/ep-event-payload.h index ae96c5cdebf97e..89d85df89be946 100644 --- a/src/native/eventpipe/ep-event-payload.h +++ b/src/native/eventpipe/ep-event-payload.h @@ -78,6 +78,8 @@ struct _EventPipeEventPayload { #endif EP_DEFINE_GETTER(EventPipeEventPayload *, event_payload, uint8_t *, data) +EP_DEFINE_GETTER(EventPipeEventPayload *, event_payload, const EventData *, event_data) +EP_DEFINE_GETTER(EventPipeEventPayload *, event_payload, uint32_t, event_data_len) EP_DEFINE_GETTER(EventPipeEventPayload *, event_payload, uint32_t, size) static diff --git a/src/native/eventpipe/ep-event-source.c b/src/native/eventpipe/ep-event-source.c index 982f75a3c531b8..7d1f8f57e4ff50 100644 --- a/src/native/eventpipe/ep-event-source.c +++ b/src/native/eventpipe/ep-event-source.c @@ -202,7 +202,7 @@ ep_event_source_enable ( ep_requires_lock_held (); bool result = true; - EventPipeSessionProvider *session_provider = ep_session_provider_alloc (event_source->provider_name, (uint64_t)-1, EP_EVENT_LEVEL_LOGALWAYS, NULL); + EventPipeSessionProvider *session_provider = ep_session_provider_alloc (event_source->provider_name, (uint64_t)-1, EP_EVENT_LEVEL_LOGALWAYS, NULL, NULL, NULL); if (session_provider != NULL) result = ep_session_add_session_provider (session, session_provider); return result; diff --git a/src/native/eventpipe/ep-provider.c b/src/native/eventpipe/ep-provider.c index 7670f23453ac46..7a2fd1cb533834 100644 --- a/src/native/eventpipe/ep-provider.c +++ b/src/native/eventpipe/ep-provider.c @@ -50,8 +50,7 @@ int64_t provider_compute_event_enable_mask ( const EventPipeConfiguration *config, const EventPipeProvider *provider, - int64_t keywords, - EventPipeEventLevel event_level); + const EventPipeEvent *ep_event); /* * EventPipeProvider. @@ -127,7 +126,7 @@ provider_refresh_event_state (EventPipeEvent *ep_event) EventPipeConfiguration *config = provider->config; EP_ASSERT (config != NULL); - int64_t enable_mask = provider_compute_event_enable_mask (config, provider, ep_event_get_keywords (ep_event), ep_event_get_level (ep_event)); + int64_t enable_mask = provider_compute_event_enable_mask (config, provider, ep_event); ep_event_set_enabled_mask (ep_event, enable_mask); ep_requires_lock_held (); @@ -139,8 +138,7 @@ int64_t provider_compute_event_enable_mask ( const EventPipeConfiguration *config, const EventPipeProvider *provider, - int64_t keywords, - EventPipeEventLevel event_level) + const EventPipeEvent *ep_event) { EP_ASSERT (provider != NULL); @@ -148,29 +146,21 @@ provider_compute_event_enable_mask ( int64_t result = 0; bool provider_enabled = ep_provider_get_enabled (provider); + if (!provider_enabled) + return result; + for (int i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; i++) { // Entering EventPipe lock gave us a barrier, we don't need more of them. EventPipeSession *session = ep_volatile_load_session_without_barrier (i); - if (session) { - EventPipeSessionProvider *session_provider = config_get_session_provider (config, session, provider); - if (session_provider) { - int64_t session_keyword = ep_session_provider_get_keywords (session_provider); - EventPipeEventLevel session_level = ep_session_provider_get_logging_level (session_provider); - // The event is enabled if: - // - The provider is enabled. - // - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0. - // - The event level is LogAlways - // or the provider's verbosity level is LogAlways - // or the provider's verbosity level is set to greater than the event's verbosity level in the manifest. - bool keyword_enabled = (keywords == 0) || ((session_keyword & keywords) != 0); - bool level_enabled = (event_level == EP_EVENT_LEVEL_LOGALWAYS) || - (session_level == EP_EVENT_LEVEL_LOGALWAYS) || - (session_level >= event_level); - - if (provider_enabled && keyword_enabled && level_enabled) - result = result | ep_session_get_mask (session); - } - } + if (session == NULL) + continue; + + EventPipeSessionProvider *session_provider = config_get_session_provider (config, session, provider); + if (session_provider == NULL) + continue; + + if (ep_session_provider_allows_event (session_provider, ep_event)) + result = result | ep_session_get_mask (session); } ep_requires_lock_held (); diff --git a/src/native/eventpipe/ep-session-provider.c b/src/native/eventpipe/ep-session-provider.c index c4bbdf5b958c3b..30ec490627cabf 100644 --- a/src/native/eventpipe/ep-session-provider.c +++ b/src/native/eventpipe/ep-session-provider.c @@ -7,6 +7,14 @@ #include "ep-session-provider.h" #include "ep-rt.h" +#if HAVE_LINUX_USER_EVENTS_H +#include // DIAG_IOCSREG +#endif // HAVE_LINUX_USER_EVENTS_H + +#if HAVE_SYS_IOCTL_H +#include // session_register_tracepoint +#endif // HAVE_SYS_IOCTL_H + /* * Forward declares of all static functions. */ @@ -23,6 +31,53 @@ session_provider_compare_name_func ( const void *a, const void *b); +static +void +session_provider_event_filter_free (EventPipeSessionProviderEventFilter *event_filter); + +static +EventPipeSessionProviderEventFilter * +session_provider_event_filter_alloc (const EventPipeProviderEventFilter *event_filter); + +static +bool +session_provider_tracepoint_register ( + EventPipeSessionProviderTracepoint *tracepoint, + int user_events_data_fd); + +static +bool +session_provider_tracepoint_unregister ( + EventPipeSessionProviderTracepoint *tracepoint, + int user_events_data_fd); + +static +void +session_provider_tracepoint_free (EventPipeSessionProviderTracepoint *tracepoint); + +static +void +DN_CALLBACK_CALLTYPE +tracepoint_free_func (void *tracepoint); + +static +void +session_provider_tracepoint_config_free (EventPipeSessionProviderTracepointConfiguration *tracepoint_config); + +static +ep_char8_t * +tracepoint_format_alloc (ep_char8_t *tracepoint_name); + +static +EventPipeSessionProviderTracepointConfiguration * +session_provider_tracepoint_config_alloc (const EventPipeProviderTracepointConfiguration *tracepoint_config); + +static +bool +event_filter_enables_event_id ( + EventPipeSessionProviderEventFilter *event_filter, + uint32_t event_id); + /* * EventPipeSessionProvider. */ @@ -45,12 +100,347 @@ session_provider_compare_name_func ( return (a) ? !ep_rt_utf8_string_compare (ep_session_provider_get_provider_name ((EventPipeSessionProvider *)a), (const ep_char8_t *)b) : false; } +static +void +session_provider_event_filter_free (EventPipeSessionProviderEventFilter *event_filter) +{ + ep_return_void_if_nok (event_filter != NULL); + + if (event_filter->event_ids != NULL) { + dn_umap_free (event_filter->event_ids); + event_filter->event_ids = NULL; + } + + ep_rt_object_free (event_filter); +} + +static +EventPipeSessionProviderEventFilter * +session_provider_event_filter_alloc (const EventPipeProviderEventFilter *event_filter) +{ + EP_ASSERT (event_filter != NULL); + + EventPipeSessionProviderEventFilter *instance = ep_rt_object_alloc (EventPipeSessionProviderEventFilter); + ep_raise_error_if_nok (instance != NULL); + + instance->enable = event_filter->enable; + + instance->event_ids = NULL; + if (event_filter->length > 0) { + instance->event_ids = dn_umap_alloc (); + ep_raise_error_if_nok (instance->event_ids != NULL); + + for (uint32_t i = 0; i < event_filter->length; ++i) { + dn_umap_result_t insert_result = dn_umap_uint32_ptr_insert (instance->event_ids, event_filter->event_ids[i], NULL); + ep_raise_error_if_nok (insert_result.result); + } + } + +ep_on_exit: + return instance; + +ep_on_error: + session_provider_event_filter_free (instance); + instance = NULL; + ep_exit_error_handler (); +} + +/* + * EventPipeSessionProviderTracepoint. + */ + +#if HAVE_LINUX_USER_EVENTS_H && HAVE_SYS_IOCTL_H +static +bool +session_provider_tracepoint_register ( + EventPipeSessionProviderTracepoint *tracepoint, + int user_events_data_fd) +{ + EP_ASSERT (tracepoint != NULL); + EP_ASSERT (user_events_data_fd != -1); + struct user_reg reg = {0}; + + reg.size = sizeof(reg); + reg.enable_bit = EP_SESSION_PROVIDER_TRACEPOINT_ENABLE_BIT; + reg.enable_size = sizeof(tracepoint->enabled); + reg.enable_addr = (uint64_t)&tracepoint->enabled; + + reg.name_args = (uint64_t)tracepoint->tracepoint_format; + + if (ioctl(user_events_data_fd, DIAG_IOCSREG, ®) == -1) + return false; + + tracepoint->write_index = reg.write_index; + + return true; +} + +static +bool +session_provider_tracepoint_unregister ( + EventPipeSessionProviderTracepoint *tracepoint, + int user_events_data_fd) +{ + EP_ASSERT (tracepoint != NULL); + EP_ASSERT (user_events_data_fd != -1); + struct user_unreg unreg = {0}; + + unreg.size = sizeof(unreg); + unreg.disable_bit = EP_SESSION_PROVIDER_TRACEPOINT_ENABLE_BIT; + unreg.disable_addr = (uint64_t)&tracepoint->enabled; + + if (ioctl(user_events_data_fd, DIAG_IOCSUNREG, &unreg) == -1) + return false; + + return true; +} +#else // HAVE_LINUX_USER_EVENTS_H && HAVE_SYS_IOCTL_H +static +bool +session_provider_tracepoint_register ( + EventPipeSessionProviderTracepoint *tracepoint, + int user_events_data_fd) +{ + // Not Supported + return false; +} + +static +bool +session_provider_tracepoint_unregister ( + EventPipeSessionProviderTracepoint *tracepoint, + int user_events_data_fd) +{ + // Not Supported + return false; +} +#endif // HAVE_LINUX_USER_EVENTS_H && HAVE_SYS_IOCTL_H + +/* + * ep_session_provider_register_tracepoints + * + * Registers the tracepoints configured for the session provider with the user events data file descriptor. + * + * Returns true if the session_provider has tracepoints and all were successfully registered. + */ +bool +ep_session_provider_register_tracepoints ( + EventPipeSessionProvider *session_provider, + int user_events_data_fd) +{ + EP_ASSERT (session_provider != NULL); + EP_ASSERT (user_events_data_fd != -1); + + if (user_events_data_fd < 0) + return false; + + EventPipeSessionProviderTracepointConfiguration *tracepoint_config = session_provider->tracepoint_config; + if (tracepoint_config == NULL) + return false; + + if (tracepoint_config->default_tracepoint.tracepoint_format == NULL && tracepoint_config->tracepoints == NULL) + return false; + + if (tracepoint_config->default_tracepoint.tracepoint_format != NULL && + !session_provider_tracepoint_register (&tracepoint_config->default_tracepoint, user_events_data_fd)) + return false; + + if (tracepoint_config->tracepoints != NULL) { + DN_VECTOR_PTR_FOREACH_BEGIN (EventPipeSessionProviderTracepoint *, tracepoint, tracepoint_config->tracepoints) { + EP_ASSERT (tracepoint != NULL); + if (!session_provider_tracepoint_register (tracepoint, user_events_data_fd)) + return false; + } DN_VECTOR_PTR_FOREACH_END; + } + + return true; +} + +/* + * ep_session_provider_unregister_tracepoints + * + * Attempts to unregister all tracepoints configured for the session provider with the user events data file descriptor. + */ +void +ep_session_provider_unregister_tracepoints ( + EventPipeSessionProvider *session_provider, + int user_events_data_fd) +{ + EP_ASSERT (session_provider != NULL); + EP_ASSERT (user_events_data_fd != -1); + + if (user_events_data_fd < 0) + return; + + if (session_provider->tracepoint_config == NULL) + return; + + EventPipeSessionProviderTracepointConfiguration *tracepoint_config = session_provider->tracepoint_config; + if (tracepoint_config->default_tracepoint.tracepoint_format != NULL) + session_provider_tracepoint_unregister (&tracepoint_config->default_tracepoint, user_events_data_fd); + + if (tracepoint_config->tracepoints != NULL) { + DN_VECTOR_PTR_FOREACH_BEGIN (EventPipeSessionProviderTracepoint *, tracepoint, tracepoint_config->tracepoints) { + EP_ASSERT (tracepoint != NULL); + session_provider_tracepoint_unregister (tracepoint, user_events_data_fd); + } DN_VECTOR_PTR_FOREACH_END; + } +} + +/* + * ep_session_provider_get_tracepoint_for_event + * + * Returns the session provider's tracepoint associated with the EventPipeEvent. + */ +const EventPipeSessionProviderTracepoint * +ep_session_provider_get_tracepoint_for_event ( + EventPipeSessionProvider *session_provider, + EventPipeEvent *ep_event) +{ + EP_ASSERT (session_provider != NULL); + EP_ASSERT (ep_event != NULL); + + EventPipeSessionProviderTracepoint *tracepoint = NULL; + EventPipeSessionProviderTracepointConfiguration *tracepoint_config = session_provider->tracepoint_config; + if (tracepoint_config == NULL) + return tracepoint; + + if (tracepoint_config->default_tracepoint.tracepoint_format != NULL) + tracepoint = &tracepoint_config->default_tracepoint; + + if (tracepoint_config->event_id_to_tracepoint_map == NULL) + return tracepoint; + + dn_umap_it_t tracepoint_found = dn_umap_uint32_ptr_find (tracepoint_config->event_id_to_tracepoint_map, ep_event_get_event_id (ep_event)); + if (!dn_umap_it_end (tracepoint_found)) + tracepoint = dn_umap_it_value_t (tracepoint_found, EventPipeSessionProviderTracepoint *); + + return tracepoint; +} + +static +void +session_provider_tracepoint_free (EventPipeSessionProviderTracepoint *tracepoint) +{ + ep_return_void_if_nok (tracepoint != NULL); + + ep_rt_utf8_string_free (tracepoint->tracepoint_format); + ep_rt_object_free (tracepoint); +} + +static +void +DN_CALLBACK_CALLTYPE +tracepoint_free_func (void *tracepoint) +{ + session_provider_tracepoint_free (*(EventPipeSessionProviderTracepoint **)tracepoint); +} + +static +void +session_provider_tracepoint_config_free (EventPipeSessionProviderTracepointConfiguration *tracepoint_config) +{ + ep_return_void_if_nok (tracepoint_config != NULL); + + if (tracepoint_config->event_id_to_tracepoint_map) { + dn_umap_free (tracepoint_config->event_id_to_tracepoint_map); + tracepoint_config->event_id_to_tracepoint_map = NULL; + } + + if (tracepoint_config->tracepoints) { + dn_vector_ptr_custom_free (tracepoint_config->tracepoints, tracepoint_free_func); + tracepoint_config->tracepoints = NULL; + } + + ep_rt_utf8_string_free (tracepoint_config->default_tracepoint.tracepoint_format); + + ep_rt_object_free (tracepoint_config); +} + +static +ep_char8_t * +tracepoint_format_alloc (ep_char8_t *tracepoint_name) +{ + EP_ASSERT (tracepoint_name != NULL); + + const int format_max_size = 512; + const ep_char8_t *args = "u8 version; u16 event_id; __rel_loc u8[] extension; __rel_loc u8[] payload"; + + if ((strlen(tracepoint_name) + strlen(args) + 2) > (size_t)format_max_size) // +2 for the space and null terminator + return NULL; + + return ep_rt_utf8_string_printf_alloc ("%s %s", tracepoint_name, args); +} + +static +EventPipeSessionProviderTracepointConfiguration * +session_provider_tracepoint_config_alloc (const EventPipeProviderTracepointConfiguration *tracepoint_config) +{ + EP_ASSERT (tracepoint_config != NULL); + + EventPipeSessionProviderTracepointConfiguration *instance = ep_rt_object_alloc (EventPipeSessionProviderTracepointConfiguration); + EventPipeSessionProviderTracepoint *tracepoint = NULL; + ep_raise_error_if_nok (instance != NULL); + + instance->default_tracepoint.tracepoint_format = NULL; + if (tracepoint_config->default_tracepoint_name != NULL) { + instance->default_tracepoint.tracepoint_format = tracepoint_format_alloc (tracepoint_config->default_tracepoint_name); + ep_raise_error_if_nok (instance->default_tracepoint.tracepoint_format != NULL); + } + + instance->tracepoints = NULL; + instance->event_id_to_tracepoint_map = NULL; + + if (tracepoint_config->non_default_tracepoints_length > 0) { + dn_vector_ptr_custom_alloc_params_t tracepoints_array_params = {0, }; + tracepoints_array_params.capacity = tracepoint_config->non_default_tracepoints_length; + instance->tracepoints = dn_vector_ptr_custom_alloc (&tracepoints_array_params); + ep_raise_error_if_nok (instance->tracepoints != NULL); + + instance->event_id_to_tracepoint_map = dn_umap_alloc (); + ep_raise_error_if_nok (instance->event_id_to_tracepoint_map != NULL); + + for (uint32_t i = 0; i < tracepoint_config->non_default_tracepoints_length; ++i) { + const EventPipeProviderTracepointSet *tracepoint_set = &tracepoint_config->non_default_tracepoints[i]; + + tracepoint = ep_rt_object_alloc (EventPipeSessionProviderTracepoint); + ep_raise_error_if_nok (tracepoint != NULL); + + tracepoint->tracepoint_format = tracepoint_format_alloc (tracepoint_set->tracepoint_name); + ep_raise_error_if_nok (tracepoint->tracepoint_format != NULL); + + for (uint32_t j = 0; j < tracepoint_set->event_ids_length; ++j) { + uint32_t event_id = tracepoint_set->event_ids[j]; + + dn_umap_result_t insert_result = dn_umap_uint32_ptr_insert (instance->event_id_to_tracepoint_map, event_id, tracepoint); + ep_raise_error_if_nok (insert_result.result); + } + + ep_raise_error_if_nok (dn_vector_ptr_push_back (instance->tracepoints, tracepoint)); + tracepoint = NULL; // Ownership transferred to the session provider tracepoint configuration. + } + } + + ep_raise_error_if_nok (instance->default_tracepoint.tracepoint_format != NULL || instance->tracepoints != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + session_provider_tracepoint_free (tracepoint); + session_provider_tracepoint_config_free (instance); + instance = NULL; + ep_exit_error_handler (); +} + EventPipeSessionProvider * ep_session_provider_alloc ( const ep_char8_t *provider_name, uint64_t keywords, EventPipeEventLevel logging_level, - const ep_char8_t *filter_data) + const ep_char8_t *filter_data, + const EventPipeProviderEventFilter *event_filter, + const EventPipeProviderTracepointConfiguration *tracepoint_config) { EventPipeSessionProvider *instance = ep_rt_object_alloc (EventPipeSessionProvider); ep_raise_error_if_nok (instance != NULL); @@ -67,6 +457,18 @@ ep_session_provider_alloc ( instance->keywords = keywords; instance->logging_level = logging_level; + instance->event_filter = NULL; + instance->tracepoint_config = NULL; + + if (event_filter) { + instance->event_filter = session_provider_event_filter_alloc (event_filter); + ep_raise_error_if_nok (instance->event_filter != NULL); + } + + if (tracepoint_config) { + instance->tracepoint_config = session_provider_tracepoint_config_alloc (tracepoint_config); + ep_raise_error_if_nok (instance->tracepoint_config != NULL); + } ep_on_exit: return instance; @@ -82,11 +484,53 @@ ep_session_provider_free (EventPipeSessionProvider * session_provider) { ep_return_void_if_nok (session_provider != NULL); + session_provider_tracepoint_config_free (session_provider->tracepoint_config); + session_provider_event_filter_free (session_provider->event_filter); ep_rt_utf8_string_free (session_provider->filter_data); ep_rt_utf8_string_free (session_provider->provider_name); ep_rt_object_free (session_provider); } +static +bool +event_filter_enables_event_id ( + EventPipeSessionProviderEventFilter *event_filter, + uint32_t event_id) +{ + if (event_filter == NULL) + return true; + + if (event_filter->event_ids == NULL) + return !event_filter->enable; + + dn_umap_it_t it = dn_umap_uint32_ptr_find (event_filter->event_ids, event_id); + bool contains_event_id = !dn_umap_it_end (it); + + return event_filter->enable == contains_event_id; +} + +bool +ep_session_provider_allows_event ( + EventPipeSessionProvider *session_provider, + const EventPipeEvent *ep_event) +{ + EP_ASSERT(session_provider != NULL); + + uint64_t keywords = ep_event_get_keywords (ep_event); + if ((keywords != 0) && ((session_provider->keywords & keywords) == 0)) + return false; + + EventPipeEventLevel event_level = ep_event_get_level (ep_event); + EventPipeEventLevel session_level = session_provider->logging_level; + if ((event_level != EP_EVENT_LEVEL_LOGALWAYS) && + (session_level != EP_EVENT_LEVEL_LOGALWAYS) && + (session_level < event_level)) + return false; + + uint32_t event_id = ep_event_get_event_id (ep_event); + return event_filter_enables_event_id (session_provider->event_filter, event_id); +} + /* * EventPipeSessionProviderList. */ @@ -114,7 +558,7 @@ ep_session_provider_list_alloc ( if ((ep_rt_utf8_string_compare(ep_provider_get_wildcard_name_utf8 (), ep_provider_config_get_provider_name (config)) == 0) && (ep_provider_config_get_keywords (config) == 0xFFFFFFFFFFFFFFFF) && ((ep_provider_config_get_logging_level (config) == EP_EVENT_LEVEL_VERBOSE) && (instance->catch_all_provider == NULL))) { - instance->catch_all_provider = ep_session_provider_alloc (NULL, 0xFFFFFFFFFFFFFFFF, EP_EVENT_LEVEL_VERBOSE, NULL ); + instance->catch_all_provider = ep_session_provider_alloc (NULL, 0xFFFFFFFFFFFFFFFF, EP_EVENT_LEVEL_VERBOSE, NULL, NULL, NULL); ep_raise_error_if_nok (instance->catch_all_provider != NULL); } else { @@ -122,7 +566,9 @@ ep_session_provider_list_alloc ( ep_provider_config_get_provider_name (config), ep_provider_config_get_keywords (config), ep_provider_config_get_logging_level (config), - ep_provider_config_get_filter_data (config)); + ep_provider_config_get_filter_data (config), + ep_provider_config_get_event_filter (config), + ep_provider_config_get_tracepoint_config (config)); ep_raise_error_if_nok (dn_list_push_back (instance->providers, session_provider)); } } diff --git a/src/native/eventpipe/ep-session-provider.h b/src/native/eventpipe/ep-session-provider.h index 31852c7ba8184d..b8c682cdb4bdf5 100644 --- a/src/native/eventpipe/ep-session-provider.h +++ b/src/native/eventpipe/ep-session-provider.h @@ -11,6 +11,94 @@ #endif #include "ep-getter-setter.h" +/* + * EventPipeSessionProviderTracepoint. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeSessionProviderTracepoint { +#else +struct _EventPipeSessionProviderTracepoint_Internal { +#endif + ep_char8_t *tracepoint_format; + uint32_t write_index; + uint32_t enabled; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeSessionProviderTracepoint { + uint8_t _internal [sizeof (struct _EventPipeSessionProviderTracepoint_Internal)]; +}; +#endif + +#define EP_SESSION_PROVIDER_TRACEPOINT_ENABLE_BIT 31 + +EP_DEFINE_GETTER(EventPipeSessionProviderTracepoint *, session_provider_tracepoint, const ep_char8_t *, tracepoint_format) +EP_DEFINE_GETTER(EventPipeSessionProviderTracepoint *, session_provider_tracepoint, uint32_t, write_index) +EP_DEFINE_GETTER(EventPipeSessionProviderTracepoint *, session_provider_tracepoint, uint32_t, enabled) + +bool +ep_session_provider_register_tracepoints ( + EventPipeSessionProvider *session_provider, + int user_events_data_fd); + +void +ep_session_provider_unregister_tracepoints ( + EventPipeSessionProvider *session_provider, + int user_events_data_fd); + +const EventPipeSessionProviderTracepoint * +ep_session_provider_get_tracepoint_for_event ( + EventPipeSessionProvider *session_provider, + EventPipeEvent *ep_event); + +/* + * EventPipeSessionProviderEventFilter. + * + * Introduced in CollectTracing5, the event filter provides EventPipe Sessions + * additional control over which events are enabled/disabled for a particular provider. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeSessionProviderEventFilter { +#else +struct _EventPipeSessionProviderEventFilter_Internal { +#endif + bool enable; + dn_umap_t *event_ids; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeSessionProviderEventFilter { + uint8_t _internal [sizeof (struct _EventPipeSessionProviderEventFilter_Internal)]; +}; +#endif + +/* + * EventPipeSessionProviderTracepointConfiguration. + * + * Introduced in CollectTracing5, user_events-based EventPipe Sessions are required to + * specify a tracepoint configuration per-provider that details which events should be + * written to which tracepoints. Atleast one of default_tracepoint_name or tracepoints + * must be specified. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeSessionProviderTracepointConfiguration { +#else +struct _EventPipeSessionProviderTracepointConfiguration_Internal { +#endif + EventPipeSessionProviderTracepoint default_tracepoint; + dn_vector_ptr_t *tracepoints; + dn_umap_t *event_id_to_tracepoint_map; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeSessionProviderTracepointConfiguration { + uint8_t _internal [sizeof (struct _EventPipeSessionProviderTracepointConfiguration_Internal)]; +}; +#endif + /* * EventPipeSessionProvider. */ @@ -24,6 +112,8 @@ struct _EventPipeSessionProvider_Internal { uint64_t keywords; EventPipeEventLevel logging_level; ep_char8_t *filter_data; + EventPipeSessionProviderEventFilter *event_filter; + EventPipeSessionProviderTracepointConfiguration *tracepoint_config; }; #if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_SESSION_PROVIDER_GETTER_SETTER) @@ -42,11 +132,18 @@ ep_session_provider_alloc ( const ep_char8_t *provider_name, uint64_t keywords, EventPipeEventLevel logging_level, - const ep_char8_t *filter_data); + const ep_char8_t *filter_data, + const EventPipeProviderEventFilter *event_filter, + const EventPipeProviderTracepointConfiguration *tracepoint_config); void ep_session_provider_free (EventPipeSessionProvider * session_provider); +bool +ep_session_provider_allows_event ( + EventPipeSessionProvider *session_provider, + const EventPipeEvent *ep_event); + /* * EventPipeSessionProviderList. */ diff --git a/src/native/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c index a8b23f8402e759..ac9cf1d7e36320 100644 --- a/src/native/eventpipe/ep-session.c +++ b/src/native/eventpipe/ep-session.c @@ -13,6 +13,18 @@ #include "ep-event-payload.h" #include "ep-rt.h" +#if HAVE_UNISTD_H +#include // close +#endif // HAVE_UNISTD_H + +#if HAVE_SYS_UIO_H +#include // iovec +#endif // HAVE_SYS_UIO_H + +#if HAVE_ERRNO_H +#include // errno +#endif // HAVE_ERRNO_H + /* * Forward declares of all static functions. */ @@ -30,6 +42,40 @@ static void ep_session_remove_dangling_session_states (EventPipeSession *session); +static +bool +session_user_events_tracepoints_init ( + EventPipeSession *session, + int user_events_data_fd); + +static +void +session_disable_user_events (EventPipeSession *session); + +static +bool +is_guid_empty(const uint8_t *guid); + +static +uint16_t +construct_extension_activity_ids_buffer ( + uint8_t *extension, + size_t extension_size, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +session_tracepoint_write_event ( + EventPipeSession *session, + ep_rt_thread_handle_t thread, + EventPipeEvent *ep_event, + EventPipeEventPayload *ep_event_payload, + const uint8_t *activity_id, + const uint8_t *related_activity_id, + ep_rt_thread_handle_t event_thread, + EventPipeStackContents *stack); + /* * EventPipeSession. */ @@ -156,6 +202,43 @@ session_disable_streaming_thread (EventPipeSession *session) ep_rt_wait_event_free (rt_thread_shutdown_event); } +/* + * session_user_events_tracepoints_init + * + * Registers all configured tracepoints for the user_events eventpipe session. + */ +static +bool +session_user_events_tracepoints_init ( + EventPipeSession *session, + int user_events_data_fd) +{ + EP_ASSERT (session != NULL); + EP_ASSERT (session->session_type == EP_SESSION_TYPE_USEREVENTS); + + bool result = false; + + EventPipeSessionProviderList *providers = session->providers; + EP_ASSERT (providers != NULL); + + ep_raise_error_if_nok (user_events_data_fd != -1); + session->user_events_data_fd = user_events_data_fd; + + DN_LIST_FOREACH_BEGIN (EventPipeSessionProvider *, session_provider, ep_session_provider_list_get_providers (providers)) { + EP_ASSERT (session_provider != NULL); + ep_raise_error_if_nok (ep_session_provider_register_tracepoints (session_provider, session->user_events_data_fd)); + } DN_LIST_FOREACH_END; + + result = true; + +ep_on_exit: + return result; + +ep_on_error: + session_disable_user_events (session); + ep_exit_error_handler (); +} + EventPipeSession * ep_session_alloc ( uint32_t index, @@ -169,11 +252,12 @@ ep_session_alloc ( const EventPipeProviderConfiguration *providers, uint32_t providers_len, EventPipeSessionSynchronousCallback sync_callback, - void *callback_additional_data) + void *callback_additional_data, + int user_events_data_fd) { EP_ASSERT (index < EP_MAX_NUMBER_OF_SESSIONS); EP_ASSERT (format < EP_SERIALIZATION_FORMAT_COUNT); - EP_ASSERT (session_type == EP_SESSION_TYPE_SYNCHRONOUS || circular_buffer_size_in_mb > 0); + EP_ASSERT (!ep_session_type_uses_buffer_manager (session_type) || circular_buffer_size_in_mb > 0); EP_ASSERT (providers_len > 0); EP_ASSERT (providers != NULL); EP_ASSERT ((sync_callback != NULL) == (session_type == EP_SESSION_TYPE_SYNCHRONOUS)); @@ -205,7 +289,7 @@ ep_session_alloc ( sequence_point_alloc_budget = 10 * 1024 * 1024; } - if (session_type != EP_SESSION_TYPE_SYNCHRONOUS) { + if (ep_session_type_uses_buffer_manager (session_type)) { instance->buffer_manager = ep_buffer_manager_alloc (instance, ((size_t)circular_buffer_size_in_mb) << 20, sequence_point_alloc_budget); ep_raise_error_if_nok (instance->buffer_manager != NULL); } @@ -233,6 +317,11 @@ ep_session_alloc ( ipc_stream_writer = NULL; break; + case EP_SESSION_TYPE_USEREVENTS: + // With the user_events_data file, register tracepoints for each provider's tracepoint configurations + ep_raise_error_if_nok (session_user_events_tracepoints_init (instance, user_events_data_fd)); + break; + default: break; } @@ -367,7 +456,9 @@ ep_session_enable_rundown (EventPipeSession *session) ep_provider_config_get_provider_name (&rundown_provider), ep_provider_config_get_keywords (&rundown_provider), ep_provider_config_get_logging_level (&rundown_provider), - ep_provider_config_get_filter_data (&rundown_provider)); + ep_provider_config_get_filter_data (&rundown_provider), + NULL, + NULL); ep_raise_error_if_nok (ep_session_add_session_provider (session, session_provider)); @@ -502,8 +593,14 @@ ep_session_disable (EventPipeSession *session) if ((session->session_type == EP_SESSION_TYPE_IPCSTREAM || session->session_type == EP_SESSION_TYPE_FILESTREAM) && ep_session_get_streaming_enabled (session)) session_disable_streaming_thread (session); - bool ignored; - ep_session_write_all_buffers_to_file (session, &ignored); + if (session->session_type == EP_SESSION_TYPE_USEREVENTS) + session_disable_user_events (session); + + if (session->file != NULL) { + bool ignored; + ep_session_write_all_buffers_to_file (session, &ignored); + } + ep_session_provider_list_clear (session->providers); } @@ -523,6 +620,248 @@ ep_session_write_all_buffers_to_file (EventPipeSession *session, bool *events_wr return !ep_file_has_errors (session->file); } +static +void +session_disable_user_events (EventPipeSession *session) +{ + EP_ASSERT (session != NULL); + ep_return_void_if_nok (session->session_type == EP_SESSION_TYPE_USEREVENTS && session->user_events_data_fd != -1); + + ep_requires_lock_held (); + + EventPipeSessionProviderList *providers = session->providers; + EP_ASSERT (providers != NULL); + DN_LIST_FOREACH_BEGIN (EventPipeSessionProvider *, session_provider, ep_session_provider_list_get_providers (providers)) { + ep_session_provider_unregister_tracepoints (session_provider, session->user_events_data_fd); + } DN_LIST_FOREACH_END; + +#if HAVE_UNISTD_H + close (session->user_events_data_fd); +#endif // HAVE_UNISTD_H + session->user_events_data_fd = -1; +} + +static +bool +is_guid_empty(const uint8_t *guid) +{ + if (guid == NULL) + return true; + + for (size_t i = 0; i < EP_ACTIVITY_ID_SIZE; ++i) { + if (guid[i] != 0) + return false; + } + + return true; +} + +/* + * construct_extension_activity_ids_buffer + * + * Encodes non-empty activity ID and related activity ID. + */ +static +uint16_t +construct_extension_activity_ids_buffer ( + uint8_t *extension, + size_t extension_size, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (extension != NULL); + EP_ASSERT (extension_size >= 2 * (1 + EP_ACTIVITY_ID_SIZE)); + uint16_t offset = 0; + + memset (extension, 0, extension_size); + + bool activity_id_is_empty = is_guid_empty (activity_id); + bool related_activity_id_is_empty = is_guid_empty (related_activity_id); + + EP_ASSERT ((size_t)(offset + 1 + EP_ACTIVITY_ID_SIZE) <= extension_size); + if (!activity_id_is_empty) { + extension[offset] = 0x02; + ++offset; + memcpy (extension + offset, activity_id, EP_ACTIVITY_ID_SIZE); + offset += EP_ACTIVITY_ID_SIZE; + } + + EP_ASSERT ((size_t)(offset + 1 + EP_ACTIVITY_ID_SIZE) <= extension_size); + if (!related_activity_id_is_empty) { + extension[offset] = 0x03; + ++offset; + memcpy (extension + offset, related_activity_id, EP_ACTIVITY_ID_SIZE); + offset += EP_ACTIVITY_ID_SIZE; + } + + return offset; +} + +#if HAVE_SYS_UIO_H && HAVE_ERRNO_H +/* + * session_tracepoint_write_event + * + * Writes the event data to the corresponding tracepoint, as configured by the session provider. + * For minimum performance overhead, this function prefers static buffers over dynamic allocations. + */ +static +bool +session_tracepoint_write_event ( + EventPipeSession *session, + ep_rt_thread_handle_t thread, + EventPipeEvent *ep_event, + EventPipeEventPayload *ep_event_payload, + const uint8_t *activity_id, + const uint8_t *related_activity_id, + ep_rt_thread_handle_t event_thread, + EventPipeStackContents *stack) +{ + EP_ASSERT (session != NULL); + EP_ASSERT (ep_event != NULL); + + EventPipeProvider *provider = ep_event_get_provider (ep_event); + EventPipeSessionProviderList *session_provider_list = session->providers; + EventPipeSessionProvider *session_provider = ep_session_provider_list_find_by_name (ep_session_provider_list_get_providers (session_provider_list), ep_provider_get_provider_name (provider)); + const EventPipeSessionProviderTracepoint *tracepoint = ep_session_provider_get_tracepoint_for_event (session_provider, ep_event); + if (tracepoint == NULL) + return false; + + if (ep_session_provider_tracepoint_get_enabled (tracepoint) == 0) + return false; + + // Setup iovec array + const int max_non_parameter_iov = 8; + const int max_static_io_capacity = 30; // Should account for most events that use EventData structs + struct iovec static_io[max_static_io_capacity]; + struct iovec *io = static_io; + + uint8_t *ep_event_data = ep_event_payload_get_data (ep_event_payload); + uint32_t ep_event_data_len = ep_event_payload_get_event_data_len (ep_event_payload); + int param_iov = ep_event_data != NULL ? 1 : ep_event_data_len; + int io_elem_capacity = param_iov + max_non_parameter_iov; + if (io_elem_capacity > max_static_io_capacity) { + io = (struct iovec *)malloc (sizeof (struct iovec) * io_elem_capacity); + if (io == NULL) + return false; + } + + int io_index = 0; + + // Write Index + uint32_t write_index = ep_session_provider_tracepoint_get_write_index (tracepoint); + io[io_index].iov_base = (void *)&write_index; + io[io_index].iov_len = sizeof(write_index); + io_index++; + + // Version + uint8_t version = 0x01; // Format V1 + io[io_index].iov_base = &version; + io[io_index].iov_len = sizeof(version); + io_index++; + + // Truncated event id + // For parity with EventSource, there shouldn't be any that need more than 16 bits. + uint16_t truncated_event_id = ep_event_get_event_id (ep_event) & 0xFFFF; + io[io_index].iov_base = &truncated_event_id; + io[io_index].iov_len = sizeof(truncated_event_id); + io_index++; + + // Extension and payload relative locations (to be fixed up later) + uint32_t extension_rel_loc = 0; + io[io_index].iov_base = &extension_rel_loc; + io[io_index].iov_len = sizeof(extension_rel_loc); + io_index++; + + uint32_t payload_rel_loc = 0; + io[io_index].iov_base = &payload_rel_loc; + io[io_index].iov_len = sizeof(payload_rel_loc); + io_index++; + + // Extension + uint32_t extension_len = 0; + + // Extension Event Metadata + uint32_t metadata_len = ep_event_get_metadata_len (ep_event); + uint8_t extension_metadata[1 + sizeof(uint32_t)]; + extension_metadata[0] = 0x01; // label + *(uint32_t*)&extension_metadata[1] = metadata_len; + io[io_index].iov_base = extension_metadata; + io[io_index].iov_len = sizeof(extension_metadata); + io_index++; + extension_len += sizeof(extension_metadata); + + io[io_index].iov_base = (void *)ep_event_get_metadata (ep_event); + io[io_index].iov_len = metadata_len; + io_index++; + extension_len += metadata_len; + + // Extension Activity IDs + const int extension_activity_ids_max_len = 2 * (1 + EP_ACTIVITY_ID_SIZE); + uint8_t extension_activity_ids[extension_activity_ids_max_len]; + uint16_t extension_activity_ids_len = construct_extension_activity_ids_buffer (extension_activity_ids, extension_activity_ids_max_len, activity_id, related_activity_id); + EP_ASSERT (extension_activity_ids_len <= extension_activity_ids_max_len); + io[io_index].iov_base = extension_activity_ids; + io[io_index].iov_len = extension_activity_ids_len; + io_index++; + extension_len += extension_activity_ids_len; + + EP_ASSERT (io_index <= max_non_parameter_iov); + + uint32_t ep_event_payload_total_size = 0; + // EventPipeEventPayload + if (ep_event_data != NULL) { + uint32_t ep_event_payload_size = ep_event_payload_get_size (ep_event_payload); + io[io_index].iov_base = ep_event_data; + io[io_index].iov_len = ep_event_payload_size; + io_index++; + ep_event_payload_total_size += ep_event_payload_size; + } else { + const EventData *event_data = ep_event_payload_get_event_data (ep_event_payload); + for (uint32_t i = 0; i < ep_event_data_len; ++i) { + uint32_t ep_event_data_size = ep_event_data_get_size (&event_data[i]); + io[io_index].iov_base = (void *)ep_event_data_get_ptr (&event_data[i]); + io[io_index].iov_len = ep_event_data_size; + io_index++; + ep_event_payload_total_size += ep_event_data_size; + } + } + + if (((extension_len & 0xFFFF0000) != 0) || ((ep_event_payload_total_size & 0xFFFF0000) != 0)) { + if (io != static_io) + free (io); + return false; + } + + // Calculate the relative locations for extension and payload. + extension_rel_loc = extension_len << 16 | (sizeof(payload_rel_loc) & 0xFFFF); + payload_rel_loc = ep_event_payload_total_size << 16 | (extension_len & 0xFFFF); + + ssize_t bytes_written; + while ((bytes_written = writev(session->user_events_data_fd, (const struct iovec *)io, io_index) < 0) && errno == EINTR); + + if (io != static_io) + free (io); + + return bytes_written != -1; +} +#else // HAVE_SYS_UIO_H && HAVE_ERRNO_H +static +bool +session_tracepoint_write_event ( + EventPipeSession *session, + ep_rt_thread_handle_t thread, + EventPipeEvent *ep_event, + EventPipeEventPayload *ep_event_payload, + const uint8_t *activity_id, + const uint8_t *related_activity_id, + ep_rt_thread_handle_t event_thread, + EventPipeStackContents *stack) +{ + // Not Supported + return false; +} +#endif // HAVE_SYS_UIO_H && HAVE_ERRNO_H + bool ep_session_write_event ( EventPipeSession *session, @@ -544,7 +883,25 @@ ep_session_write_event ( // Filter events specific to "this" session based on precomputed flag on provider/events. if (ep_event_is_enabled_by_mask (ep_event, ep_session_get_mask (session))) { - if (session->synchronous_callback) { + switch (session->session_type) { + case EP_SESSION_TYPE_FILE: + case EP_SESSION_TYPE_LISTENER: + case EP_SESSION_TYPE_IPCSTREAM: + case EP_SESSION_TYPE_FILESTREAM: + EP_ASSERT (session->buffer_manager != NULL); + result = ep_buffer_manager_write_event ( + session->buffer_manager, + thread, + session, + ep_event, + payload, + activity_id, + related_activity_id, + event_thread, + stack); + break; + case EP_SESSION_TYPE_SYNCHRONOUS: + EP_ASSERT (session->synchronous_callback != NULL); session->synchronous_callback ( ep_event_get_provider (ep_event), ep_event_get_event_id (ep_event), @@ -560,18 +917,22 @@ ep_session_write_event ( stack == NULL ? NULL : (uintptr_t *)ep_stack_contents_get_pointer (stack), session->callback_additional_data); result = true; - } else { - EP_ASSERT (session->buffer_manager != NULL); - result = ep_buffer_manager_write_event ( - session->buffer_manager, - thread, + break; + case EP_SESSION_TYPE_USEREVENTS: + EP_ASSERT (session->user_events_data_fd != -1); + result = session_tracepoint_write_event ( session, + thread, ep_event, payload, activity_id, related_activity_id, event_thread, stack); + break; + default: + EP_UNREACHABLE ("Unknown session type."); + break; } } @@ -665,6 +1026,12 @@ ep_session_has_started (EventPipeSession *session) return ep_rt_volatile_load_uint32_t (&session->started) == 1 ? true : false; } +bool +ep_session_type_uses_buffer_manager (EventPipeSessionType session_type) +{ + return (session_type != EP_SESSION_TYPE_SYNCHRONOUS && session_type != EP_SESSION_TYPE_USEREVENTS); +} + #endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ #endif /* ENABLE_PERFTRACING */ diff --git a/src/native/eventpipe/ep-session.h b/src/native/eventpipe/ep-session.h index 90b733751301d5..56af80bf3438ed 100644 --- a/src/native/eventpipe/ep-session.h +++ b/src/native/eventpipe/ep-session.h @@ -69,6 +69,8 @@ struct _EventPipeSession_Internal { volatile uint32_t started; // Reference count for the session. This is used to track the number of references to the session. volatile uint32_t ref_count; + // The user_events_data file descriptor to register Tracepoints and write user_events to. + int user_events_data_fd; }; #if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_SESSION_GETTER_SETTER) @@ -100,7 +102,8 @@ ep_session_alloc ( const EventPipeProviderConfiguration *providers, uint32_t providers_len, EventPipeSessionSynchronousCallback sync_callback, - void *callback_additional_data); + void *callback_additional_data, + int user_events_data_fd); void ep_session_inc_ref (EventPipeSession *session); @@ -214,5 +217,8 @@ ep_session_resume (EventPipeSession *session); bool ep_session_has_started (EventPipeSession *session); +bool +ep_session_type_uses_buffer_manager (EventPipeSessionType session_type); + #endif /* ENABLE_PERFTRACING */ #endif /* __EVENTPIPE_SESSION_H__ */ diff --git a/src/native/eventpipe/ep-shared-config.h.in b/src/native/eventpipe/ep-shared-config.h.in index 526b45cbb7d99c..0eeb73e1dcb4f2 100644 --- a/src/native/eventpipe/ep-shared-config.h.in +++ b/src/native/eventpipe/ep-shared-config.h.in @@ -1,7 +1,13 @@ #ifndef EP_SHARED_CONFIG_H_INCLUDED #define EP_SHARED_CONFIG_H_INCLUDED +#cmakedefine01 HAVE_ERRNO_H +#cmakedefine01 HAVE_LINUX_USER_EVENTS_H +#cmakedefine01 HAVE_SYS_IOCTL_H #cmakedefine01 HAVE_SYS_SOCKET_H +#cmakedefine01 HAVE_SYS_UIO_H +/* mono files use ifdef HAVE_UNISTD_H, so for compatibility */ +#cmakedefine HAVE_UNISTD_H 1 /* This platforms supports setting flags atomically when accepting connections. */ #cmakedefine01 HAVE_ACCEPT4 diff --git a/src/native/eventpipe/ep-string.c b/src/native/eventpipe/ep-string.c index a41b50104de455..04afaa0e484597 100644 --- a/src/native/eventpipe/ep-string.c +++ b/src/native/eventpipe/ep-string.c @@ -8,6 +8,7 @@ #include "ep-rt.h" #include +#include // va_list, va_start, va_end static ep_char16_t * @@ -133,6 +134,42 @@ ep_rt_utf16le_to_utf8_string_n ( return ep_utf16_to_utf8_string_impl(str, len, /*treat_as_le*/ true); } +ep_char8_t * +ep_rt_utf8_string_printf_alloc (const ep_char8_t *format, ...) +{ + if (!format) + return NULL; + + va_list args; + va_start (args, format); + + va_list args_copy; + va_copy (args_copy, args); + int len = vsnprintf (NULL, 0, format, args_copy); + va_end (args_copy); + if (len < 0) { + va_end (args); + return NULL; + } + + size_t size = (size_t)len + 1; + ep_char8_t *buffer = ep_rt_utf8_string_alloc (size); + if (!buffer) { + va_end (args); + return NULL; + } + + int written = vsnprintf (buffer, size, format, args); + va_end (args); + + if (written < 0 || (size_t)written >= size) { + ep_rt_utf8_string_free (buffer); + return NULL; + } + + return buffer; +} + #endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ #endif /* ENABLE_PERFTRACING */ diff --git a/src/native/eventpipe/ep-string.h b/src/native/eventpipe/ep-string.h index 6adb8e99d160f9..fc14844a4ff235 100644 --- a/src/native/eventpipe/ep-string.h +++ b/src/native/eventpipe/ep-string.h @@ -60,5 +60,9 @@ ep_rt_utf16le_to_utf8_string_n ( const ep_char16_t *str, size_t len); +// Allocates a new UTF-8 string and formats it according to the specified format and arguments. +ep_char8_t * +ep_rt_utf8_string_printf_alloc (const ep_char8_t *format, ...); + #endif /* ENABLE_PERFTRACING */ #endif /* EVENTPIPE_STRING_H */ diff --git a/src/native/eventpipe/ep-types-forward.h b/src/native/eventpipe/ep-types-forward.h index 4e3b218291506d..0aa597b155fdb7 100644 --- a/src/native/eventpipe/ep-types-forward.h +++ b/src/native/eventpipe/ep-types-forward.h @@ -31,10 +31,15 @@ typedef struct _EventPipeProvider EventPipeProvider; typedef struct _EventPipeProviderCallbackData EventPipeProviderCallbackData; typedef struct _EventPipeProviderCallbackDataQueue EventPipeProviderCallbackDataQueue; typedef struct _EventPipeProviderConfiguration EventPipeProviderConfiguration; +typedef struct _EventPipeProviderEventFilter EventPipeProviderEventFilter; +typedef struct _EventPipeProviderTracepointConfiguration EventPipeProviderTracepointConfiguration; +typedef struct _EventPipeProviderTracepointSet EventPipeProviderTracepointSet; typedef struct _EventPipeExecutionCheckpoint EventPipeExecutionCheckpoint; typedef struct _EventPipeSession EventPipeSession; typedef struct _EventPipeSessionProvider EventPipeSessionProvider; +typedef struct _EventPipeSessionProviderEventFilter EventPipeSessionProviderEventFilter; typedef struct _EventPipeSessionProviderList EventPipeSessionProviderList; +typedef struct _EventPipeSessionProviderTracepointConfiguration EventPipeSessionProviderTracepointConfiguration; typedef struct _EventPipeSequencePoint EventPipeSequencePoint; typedef struct _EventPipeSequencePointBlock EventPipeSequencePointBlock; typedef struct _EventPipeStackBlock EventPipeStackBlock; @@ -44,6 +49,7 @@ typedef struct _EventPipeSystemTime EventPipeSystemTime; typedef struct _EventPipeThread EventPipeThread; typedef struct _EventPipeThreadHolder EventPipeThreadHolder; typedef struct _EventPipeThreadSessionState EventPipeThreadSessionState; +typedef struct _EventPipeSessionProviderTracepoint EventPipeSessionProviderTracepoint; typedef struct _FastSerializableObject FastSerializableObject; typedef struct _FastSerializableObjectVtable FastSerializableObjectVtable; typedef struct _FastSerializer FastSerializer; @@ -147,7 +153,8 @@ typedef enum { EP_SESSION_TYPE_LISTENER, EP_SESSION_TYPE_IPCSTREAM, EP_SESSION_TYPE_SYNCHRONOUS, - EP_SESSION_TYPE_FILESTREAM + EP_SESSION_TYPE_FILESTREAM, + EP_SESSION_TYPE_USEREVENTS } EventPipeSessionType ; typedef enum { diff --git a/src/native/eventpipe/ep-types.h b/src/native/eventpipe/ep-types.h index 7a16bc77a3466f..bb2b6223a504f5 100644 --- a/src/native/eventpipe/ep-types.h +++ b/src/native/eventpipe/ep-types.h @@ -175,6 +175,84 @@ ep_provider_callback_data_queue_try_dequeue ( EventPipeProviderCallbackDataQueue *provider_callback_data_queue, EventPipeProviderCallbackData *provider_callback_data); +/* + * EventPipeProviderEventFilter. + * + * Used as read-only data to configure a SessionProvider's set EventFilter, + * matching the DiagnosticServer IPC Protocol encoding specification. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeProviderEventFilter { +#else +struct _EventPipeProviderEventFilter_Internal { +#endif + bool enable; + uint32_t length; + uint32_t *event_ids; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeProviderEventFilter { + uint8_t _internal [sizeof (struct _EventPipeProviderEventFilter_Internal)]; +}; +#endif + +void +eventpipe_collect_tracing_command_free_event_filter (EventPipeProviderEventFilter *event_filter); + +/* + * EventPipeProviderTracepointSet. + * + * Used as read-only data to configure a Tracepoint Configuration's set of non-default + * tracepoints, matching the DiagnosticServer IPC Protocol encoding specification. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeProviderTracepointSet { +#else +struct _EventPipeProviderTracepointSet_Internal { +#endif + ep_char8_t *tracepoint_name; + uint32_t *event_ids; + uint32_t event_ids_length; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeProviderTracepointSet { + uint8_t _internal [sizeof (struct _EventPipeProviderTracepointSet_Internal)]; +}; +#endif + +void +eventpipe_collect_tracing_command_free_tracepoint_sets (EventPipeProviderTracepointSet *tracepoint_sets, uint32_t tracepoint_sets_len); + +/* + * EventPipeProviderTracepointConfiguration. + * + * Used as read-only data to configure the SessionProvider's Tracepoint + * configuration, matching the DiagnosticServer IPC Protocol encoding specification. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeProviderTracepointConfiguration { +#else +struct _EventPipeProviderTracepointConfiguration_Internal { +#endif + ep_char8_t *default_tracepoint_name; + EventPipeProviderTracepointSet *non_default_tracepoints; + uint32_t non_default_tracepoints_length; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_EP_GETTER_SETTER) +struct _EventPipeProviderTracepointConfiguration { + uint8_t _internal [sizeof (struct _EventPipeProviderTracepointConfiguration_Internal)]; +}; +#endif + +void +eventpipe_collect_tracing_command_free_tracepoint_config (EventPipeProviderTracepointConfiguration *tracepoint_config); + /* * EventPipeProviderConfiguration. */ @@ -184,10 +262,12 @@ struct _EventPipeProviderConfiguration { #else struct _EventPipeProviderConfiguration_Internal { #endif - const ep_char8_t *provider_name; - const ep_char8_t *filter_data; + ep_char8_t *provider_name; + ep_char8_t *filter_data; uint64_t keywords; EventPipeEventLevel logging_level; + EventPipeProviderEventFilter *event_filter; + EventPipeProviderTracepointConfiguration *tracepoint_config; }; @@ -201,6 +281,8 @@ EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, const ep_cha EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, const ep_char8_t *, filter_data) EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, uint64_t, keywords) EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, EventPipeEventLevel, logging_level) +EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, const EventPipeProviderEventFilter *, event_filter) +EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, const EventPipeProviderTracepointConfiguration *, tracepoint_config) EventPipeProviderConfiguration * ep_provider_config_init ( diff --git a/src/native/eventpipe/ep.c b/src/native/eventpipe/ep.c index 45e853febed841..b67c825b982a64 100644 --- a/src/native/eventpipe/ep.c +++ b/src/native/eventpipe/ep.c @@ -358,6 +358,41 @@ ep_provider_callback_data_free (EventPipeProviderCallbackData *provider_callback ep_rt_object_free (provider_callback_data); } +void +eventpipe_collect_tracing_command_free_event_filter (EventPipeProviderEventFilter *event_filter) +{ + ep_return_void_if_nok (event_filter != NULL); + + ep_rt_object_array_free (event_filter->event_ids); + + ep_rt_object_free (event_filter); +} + +void +eventpipe_collect_tracing_command_free_tracepoint_sets (EventPipeProviderTracepointSet *tracepoint_sets, uint32_t tracepoint_sets_len) +{ + ep_return_void_if_nok (tracepoint_sets != NULL); + + for (uint32_t i = 0; i < tracepoint_sets_len; ++i) { + ep_rt_utf8_string_free (tracepoint_sets[i].tracepoint_name); + ep_rt_object_array_free (tracepoint_sets[i].event_ids); + } + + ep_rt_object_array_free (tracepoint_sets); +} + +void +eventpipe_collect_tracing_command_free_tracepoint_config (EventPipeProviderTracepointConfiguration *tracepoint_config) +{ + ep_return_void_if_nok (tracepoint_config != NULL); + + ep_rt_utf8_string_free (tracepoint_config->default_tracepoint_name); + + eventpipe_collect_tracing_command_free_tracepoint_sets (tracepoint_config->non_default_tracepoints, tracepoint_config->non_default_tracepoints_length); + + ep_rt_object_free (tracepoint_config); +} + /* * EventPipeProviderConfiguration. */ @@ -373,10 +408,16 @@ ep_provider_config_init ( EP_ASSERT (provider_config != NULL); EP_ASSERT (provider_name != NULL); - provider_config->provider_name = provider_name; + provider_config->provider_name = ep_rt_utf8_string_dup (provider_name); provider_config->keywords = keywords; provider_config->logging_level = logging_level; - provider_config->filter_data = filter_data; + provider_config->filter_data = NULL; + if (filter_data != NULL) + provider_config->filter_data = ep_rt_utf8_string_dup (filter_data); + + // Currently only supported through IPC Command + provider_config->event_filter = NULL; + provider_config->tracepoint_config = NULL; // Runtime specific rundown provider configuration. ep_rt_provider_config_init (provider_config); @@ -387,7 +428,12 @@ ep_provider_config_init ( void ep_provider_config_fini (EventPipeProviderConfiguration *provider_config) { - ; + ep_return_void_if_nok (provider_config != NULL); + + ep_rt_utf8_string_free (provider_config->provider_name); + ep_rt_utf8_string_free (provider_config->filter_data); + eventpipe_collect_tracing_command_free_event_filter (provider_config->event_filter); + eventpipe_collect_tracing_command_free_tracepoint_config (provider_config->tracepoint_config); } /* @@ -469,7 +515,7 @@ static bool check_options_valid (const EventPipeSessionOptions *options) { if (options->format >= EP_SERIALIZATION_FORMAT_COUNT) return false; - if (options->circular_buffer_size_in_mb <= 0 && options->session_type != EP_SESSION_TYPE_SYNCHRONOUS) + if (options->circular_buffer_size_in_mb <= 0 && ep_session_type_uses_buffer_manager (options->session_type)) return false; if (options->providers == NULL || options->providers_len <= 0) return false; @@ -477,6 +523,9 @@ static bool check_options_valid (const EventPipeSessionOptions *options) return false; if (options->session_type == EP_SESSION_TYPE_IPCSTREAM && options->stream == NULL) return false; + // More UserEvents specific checks can be added here. + if (options->session_type == EP_SESSION_TYPE_USEREVENTS && options->user_events_data_fd == -1) + return false; return true; } @@ -491,7 +540,7 @@ enable ( EP_ASSERT (options != NULL); EP_ASSERT (options->format < EP_SERIALIZATION_FORMAT_COUNT); - EP_ASSERT (options->session_type == EP_SESSION_TYPE_SYNCHRONOUS || options->circular_buffer_size_in_mb > 0); + EP_ASSERT (!ep_session_type_uses_buffer_manager (options->session_type) || options->circular_buffer_size_in_mb > 0); EP_ASSERT (options->providers_len > 0 && options->providers != NULL); EventPipeSession *session = NULL; @@ -515,7 +564,8 @@ enable ( options->providers, options->providers_len, options->sync_callback, - options->callback_additional_data); + options->callback_additional_data, + options->user_events_data_fd); ep_raise_error_if_nok (session != NULL && ep_session_is_valid (session)); @@ -601,7 +651,7 @@ disable_holding_lock ( // Disable session tracing. config_enable_disable (ep_config_get (), session, provider_callback_data_queue, false); - ep_session_disable (session); // WriteAllBuffersToFile, and remove providers. + ep_session_disable (session); // WriteAllBuffersToFile, disable user_events, and remove providers. // Do rundown before fully stopping the session unless rundown wasn't requested if ((ep_session_get_rundown_keyword (session) != 0) && _ep_can_start_threads) { @@ -984,7 +1034,7 @@ ep_enable ( EventPipeSessionID sessionId = 0; EventPipeSessionOptions options; - ep_session_options_init( + ep_session_options_init ( &options, output_path, circular_buffer_size_in_mb, @@ -996,11 +1046,12 @@ ep_enable ( true, // stackwalk_requested stream, sync_callback, - callback_additional_data); + callback_additional_data, + 0); - sessionId = ep_enable_3(&options); + sessionId = ep_enable_3 (&options); - ep_session_options_fini(&options); + ep_session_options_fini (&options); return sessionId; } @@ -1031,9 +1082,9 @@ ep_enable_2 ( providers = ep_rt_object_array_alloc (EventPipeProviderConfiguration, providers_len); ep_raise_error_if_nok (providers != NULL); - ep_provider_config_init (&providers [0], ep_rt_utf8_string_dup (ep_config_get_public_provider_name_utf8 ()), 0x4c14fccbd, EP_EVENT_LEVEL_VERBOSE, NULL); - ep_provider_config_init (&providers [1], ep_rt_utf8_string_dup (ep_config_get_private_provider_name_utf8 ()), 0x4002000b, EP_EVENT_LEVEL_VERBOSE, NULL); - ep_provider_config_init (&providers [2], ep_rt_utf8_string_dup (ep_config_get_sample_profiler_provider_name_utf8 ()), 0x0, EP_EVENT_LEVEL_VERBOSE, NULL); + ep_provider_config_init (&providers [0], ep_config_get_public_provider_name_utf8 (), 0x4c14fccbd, EP_EVENT_LEVEL_VERBOSE, NULL); + ep_provider_config_init (&providers [1], ep_config_get_private_provider_name_utf8 (), 0x4002000b, EP_EVENT_LEVEL_VERBOSE, NULL); + ep_provider_config_init (&providers [2], ep_config_get_sample_profiler_provider_name_utf8 (), 0x0, EP_EVENT_LEVEL_VERBOSE, NULL); } else { // Count number of providers to parse. while (*providers_config_to_parse != '\0') { @@ -1071,6 +1122,8 @@ ep_enable_2 ( args = get_next_config_value_as_utf8_string (&providers_config_to_parse); ep_provider_config_init (&providers [current_provider++], provider_name, keyword_mask, level, args); + ep_rt_utf8_string_free (provider_name); + ep_rt_utf8_string_free (args); if (!providers_config_to_parse) break; @@ -1098,11 +1151,8 @@ ep_enable_2 ( ep_on_exit: if (providers) { - for (int32_t i = 0; i < providers_len; ++i) { + for (int32_t i = 0; i < providers_len; ++i) ep_provider_config_fini (&providers [i]); - ep_rt_utf8_string_free ((ep_char8_t *)providers [i].provider_name); - ep_rt_utf8_string_free ((ep_char8_t *)providers [i].filter_data); - } ep_rt_object_array_free (providers); } @@ -1126,7 +1176,8 @@ ep_session_options_init ( bool stackwalk_requested, IpcStream* stream, EventPipeSessionSynchronousCallback sync_callback, - void* callback_additional_data) + void* callback_additional_data, + int user_events_data_fd) { EP_ASSERT (options != NULL); @@ -1141,6 +1192,7 @@ ep_session_options_init ( options->stream = stream; options->sync_callback = sync_callback; options->callback_additional_data = callback_additional_data; + options->user_events_data_fd = user_events_data_fd; } void diff --git a/src/native/eventpipe/ep.h b/src/native/eventpipe/ep.h index fd8c019121c1e3..e82b247e4186ba 100644 --- a/src/native/eventpipe/ep.h +++ b/src/native/eventpipe/ep.h @@ -127,6 +127,7 @@ typedef struct EventPipeSessionOptions { EventPipeSerializationFormat format; uint64_t rundown_keyword; bool stackwalk_requested; + int user_events_data_fd; } EventPipeSessionOptions; void @@ -142,7 +143,8 @@ ep_session_options_init ( bool stackwalk_requested, IpcStream *stream, EventPipeSessionSynchronousCallback sync_callback, - void *callback_additional_data); + void *callback_additional_data, + int user_events_data_fd); void ep_session_options_fini (EventPipeSessionOptions* options);