From b2bce62858cb0aaf9cd294a5d1540a422d2c4ef2 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Tue, 19 Jan 2021 13:45:51 +0100 Subject: [PATCH 1/8] Add Mono EventPipe rundown support. Add support into Mono VM emitting rundown events into EventPipe stream. All rundown events emitted by CoreClr during EventPipe rundown phase are now also emitted by Mono, making sure enough meta information is available for tooling to correctly resolve callstacks (not yet emitted) included in EventPipe events emitted by Mono VM. --- src/mono/mono/eventpipe/ep-rt-mono.c | 1246 +++++++++++++++++++ src/mono/mono/eventpipe/ep-rt-mono.h | 30 +- src/mono/mono/metadata/domain-internals.h | 5 + src/mono/mono/metadata/jit-info.c | 27 + src/native/eventpipe/ds-process-protocol.c | 2 +- src/native/eventpipe/ds-process-protocol.h | 2 +- src/native/eventpipe/ds-profiler-protocol.h | 2 +- src/native/eventpipe/ds-protocol.c | 6 +- src/native/eventpipe/ep-types.h | 4 +- 9 files changed, 1315 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 07e019e6642800..bf8c9844280023 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -4,7 +4,14 @@ #include #include #include +#include +#include #include +#include +#include +#include +#include +#include ep_rt_spin_lock_handle_t _ep_rt_mono_config_lock = {0}; EventPipeMonoFuncTable _ep_rt_mono_func_table = {0}; @@ -276,6 +283,1245 @@ ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) #endif } +// Rundown flags. +#define RUNTIME_SKU_CORECLR 0x2 + +#define METHOD_FLAGS_DYNAMIC_METHOD 0x1 +#define METHOD_FLAGS_GENERIC_METHOD 0x2 +#define METHOD_FLAGS_SHARED_GENERIC_METHOD 0x4 +#define METHOD_FLAGS_JITTED_METHOD 0x8 +#define METHOD_FLAGS_JITTED_HELPER_METHOD 0x10 + +#define MODULE_FLAGS_NATIVE_MODULE 0x2 +#define MODULE_FLAGS_DYNAMIC_MODULE 0x4 +#define MODULE_FLAGS_MANIFEST_MODULE 0x8 + +#define ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY 0x2 +#define ASSEMBLY_FLAGS_NATIVE_ASSEMBLY 0x4 +#define ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY 0x8 + +#define DOMAIN_FLAGS_DEFAULT_DOMAIN 0x1 +#define DOMAIN_FLAGS_EXECUTABLE_DOMAIN 0x2 + +// Rundown events. +EventPipeProvider *EventPipeProviderDotNETRuntimeRundown = NULL; +EventPipeEvent *EventPipeEventMethodDCEndVerbose_V1 = NULL; +EventPipeEvent *EventPipeEventDCEndInit_V1 = NULL; +EventPipeEvent *EventPipeEventDCEndComplete_V1 = NULL; +EventPipeEvent *EventPipeEventMethodDCEndILToNativeMap = NULL; +EventPipeEvent *EventPipeEventDomainModuleDCEnd_V1 = NULL; +EventPipeEvent *EventPipeEventModuleDCEnd_V2 = NULL; +EventPipeEvent *EventPipeEventAssemblyDCEnd_V1 = NULL; +EventPipeEvent *EventPipeEventAppDomainDCEnd_V1 = NULL; +EventPipeEvent *EventPipeEventRuntimeInformationDCStart = NULL; + +/* + * Forward declares of all static rundown functions. + */ + +static +bool +resize_buffer ( + uint8_t **buffer, + size_t *size, + size_t current_size, + size_t new_size, + bool *fixed_buffer); + +static +bool +write_buffer ( + const uint8_t *value, + size_t value_size, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer); + +static +bool +write_buffer_string_utf8_t ( + const ep_char8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer); + +static +bool +write_runtime_info_dc_start ( + const uint16_t clr_instance_id, + const uint16_t sku_id, + const uint16_t bcl_major_version, + const uint16_t bcl_minor_version, + const uint16_t bcl_build_number, + const uint16_t bcl_qfe_number, + const uint16_t vm_major_version, + const uint16_t vm_minor_version, + const uint16_t vm_build_number, + const uint16_t vm_qfe_number, + const uint32_t startup_flags, + const uint8_t startup_mode, + const ep_char8_t *cmd_line, + const uint8_t * object_guid, + const ep_char8_t *runtime_dll_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_runtime_info_dc_start ( + const uint16_t clr_instance_id, + const uint16_t sku_id, + const uint16_t bcl_major_version, + const uint16_t bcl_minor_version, + const uint16_t bcl_build_number, + const uint16_t bcl_qfe_number, + const uint16_t vm_major_version, + const uint16_t vm_minor_version, + const uint16_t vm_build_number, + const uint16_t vm_qfe_number, + const uint32_t startup_flags, + const uint8_t startup_mode, + const ep_char8_t *cmd_line, + const uint8_t * object_guid, + const ep_char8_t *runtime_dll_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_event_dc_end_complete_v1 ( + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_event_method_dc_end_il_to_native_map ( + const uint64_t method_id, + const uint64_t rejit_id, + const uint8_t method_extent, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_event_method_dc_end_verbose_v1 ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_event_module_dc_end_v2 ( + const uint64_t module_id, + const uint64_t assembly_id, + const uint32_t module_flags, + const uint32_t reserved_1, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_event_module_dc_end_v2 ( + const uint64_t module_id, + const uint64_t assembly_id, + const uint32_t module_flags, + const uint32_t reserved_1, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_event_assembly_dc_end_v1 ( + const uint64_t assembly_id, + const uint64_t domain_id, + const uint64_t binding_id, + const uint32_t assembly_flags, + const ep_char8_t *fully_qualified_name, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +write_event_domain_dc_end_v1 ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +bool +try_fire_method_il_to_native_map_using_debug_info ( + MonoMethod *method, + MonoDomain *domain); + +static +void +fire_method_il_to_native_map ( + MonoJitInfo *ji, + MonoDomain *domain); + +static +void +fire_method_verbose_v1 ( + MonoJitInfo *ji, + MonoDomain *domain); + +static +void +fire_method_events ( + MonoJitInfo *ji, + gpointer user_data); + +static +void +fire_assembly_events ( + MonoDomain *domain, + MonoAssembly *assembly); + +static +void +init_dotnet_runtime_rundown (void); + +static +inline +uint16_t +clr_instance_get_id (void) +{ + // Mono runtime id. + return 9; +} + +static +bool +resize_buffer ( + uint8_t **buffer, + size_t *size, + size_t current_size, + size_t new_size, + bool *fixed_buffer) +{ + EP_ASSERT (buffer != NULL); + EP_ASSERT (size != NULL); + EP_ASSERT (fixed_buffer != NULL); + + new_size = (size_t)(new_size * 1.5); + if (new_size < *size) { + EP_ASSERT (!"Overflow"); + return false; + } + + if (new_size < 32) + new_size = 32; + + uint8_t *new_buffer; + new_buffer = ep_rt_byte_array_alloc (new_size); + ep_raise_error_if_nok (new_buffer != NULL); + + memcpy (new_buffer, *buffer, current_size); + + if (!*fixed_buffer) + ep_rt_byte_array_free (*buffer); + + *buffer = new_buffer; + *size = new_size; + *fixed_buffer = false; + + return true; + +ep_on_error: + return false; +} + +static +bool +write_buffer ( + const uint8_t *value, + size_t value_size, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + EP_ASSERT (value != NULL); + EP_ASSERT (buffer != NULL); + EP_ASSERT (offset != NULL); + EP_ASSERT (size != NULL); + EP_ASSERT (fixed_buffer != NULL); + + if ((value_size + *offset) > *size) + ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + value_size, fixed_buffer)); + + memcpy (*buffer + *offset, value, value_size); + *offset += value_size; + + return true; + +ep_on_error: + return false; +} + +static +bool +write_buffer_string_utf8_t ( + const ep_char8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + if (!value) + return true; + + bool result = false; + ep_char16_t *value_utf16 = NULL; + + // TODO: Implement conversion into output buffer, eliminate heap allocation. + value_utf16 = ep_rt_utf8_to_utf16_string (value, -1); + ep_raise_error_if_nok (value_utf16 != NULL); + + size_t value_utf16_size; + value_utf16_size = (ep_rt_utf16_string_len (value_utf16) + 1) * sizeof (ep_char16_t); + + if ((value_utf16_size + *offset) > *size) + ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + value_utf16_size, fixed_buffer)); + + memcpy (*buffer + *offset, value_utf16, value_utf16_size); + *offset += value_utf16_size; + + result = true; + +ep_on_exit: + ep_rt_utf16_string_free (value_utf16); + return result; + +ep_on_error: + ep_exit_error_handler (); +} + +static +inline +bool +write_buffer_guid_t ( + const uint8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer (value, EP_GUID_SIZE, buffer, offset, size, fixed_buffer); +} + +static +inline +bool +write_buffer_uint8_t ( + const uint8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer (value, sizeof (uint8_t), buffer, offset, size, fixed_buffer); +} + +static +inline +bool +write_buffer_uint16_t ( + const uint16_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer ((const uint8_t *)value, sizeof (uint16_t), buffer, offset, size, fixed_buffer); +} + +static +inline +bool +write_buffer_uint32_t ( + const uint32_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer ((const uint8_t *)value, sizeof (uint32_t), buffer, offset, size, fixed_buffer); +} + +static +inline +bool +write_buffer_uint64_t ( + const uint64_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer ((const uint8_t *)value, sizeof (uint64_t), buffer, offset, size, fixed_buffer); +} + +static +bool +write_runtime_info_dc_start ( + const uint16_t clr_instance_id, + const uint16_t sku_id, + const uint16_t bcl_major_version, + const uint16_t bcl_minor_version, + const uint16_t bcl_build_number, + const uint16_t bcl_qfe_number, + const uint16_t vm_major_version, + const uint16_t vm_minor_version, + const uint16_t vm_build_number, + const uint16_t vm_qfe_number, + const uint32_t startup_flags, + const uint8_t startup_mode, + const ep_char8_t *cmd_line, + const uint8_t * object_guid, + const ep_char8_t *runtime_dll_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventRuntimeInformationDCStart != NULL); + + if (!ep_event_is_enabled (EventPipeEventRuntimeInformationDCStart)) + return true; + + uint8_t stack_buffer [153]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&sku_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_major_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_minor_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_build_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_qfe_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_major_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_minor_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_build_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_qfe_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&startup_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint8_t (&startup_mode, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (cmd_line, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_guid_t (object_guid, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (runtime_dll_path, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventRuntimeInformationDCStart, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_dc_end_init_v1 ( + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventDCEndInit_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventDCEndInit_V1)) + return true; + + uint8_t stack_buffer [32]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventDCEndInit_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_dc_end_complete_v1 ( + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventDCEndComplete_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventDCEndComplete_V1)) + return true; + + uint8_t stack_buffer [32]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventDCEndComplete_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_method_dc_end_il_to_native_map ( + const uint64_t method_id, + const uint64_t rejit_id, + const uint8_t method_extent, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventMethodDCEndILToNativeMap != NULL); + + if (!ep_event_is_enabled (EventPipeEventMethodDCEndILToNativeMap)) + return true; + + uint8_t stack_buffer [32]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&method_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&rejit_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint8_t (&method_extent, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer ((const uint8_t *)il_offsets, sizeof (const uint32_t) * (int32_t)count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer ((const uint8_t *)native_offsets, sizeof (const uint32_t) * (int32_t)count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventMethodDCEndILToNativeMap, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_method_dc_end_verbose_v1 ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventMethodDCEndVerbose_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventMethodDCEndVerbose_V1)) + return true; + + uint8_t stack_buffer [230]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&method_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&method_start_address, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&method_size, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&method_token, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&method_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (method_namespace, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (method_name, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (method_signature, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventMethodDCEndVerbose_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_module_dc_end_v2 ( + const uint64_t module_id, + const uint64_t assembly_id, + const uint32_t module_flags, + const uint32_t reserved_1, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventModuleDCEnd_V2 != NULL); + + if (!ep_event_is_enabled (EventPipeEventModuleDCEnd_V2)) + return true; + + uint8_t stack_buffer [290]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&module_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&reserved_1, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_il_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_native_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_guid_t (managed_pdb_signature, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&managed_pdb_age, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (managed_pdb_build_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_guid_t (native_pdb_signature, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&native_pdb_age, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (native_pdb_build_path, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventModuleDCEnd_V2, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_domain_module_dc_end_v1 ( + const uint64_t module_id, + const uint64_t assembly_id, + const uint64_t domain_id, + const uint32_t module_flags, + const uint32_t reserved_1, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventDomainModuleDCEnd_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventDomainModuleDCEnd_V1)) + return true; + + uint8_t stack_buffer [162]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&module_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&reserved_1, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_il_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_native_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventDomainModuleDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_assembly_dc_end_v1 ( + const uint64_t assembly_id, + const uint64_t domain_id, + const uint64_t binding_id, + const uint32_t assembly_flags, + const ep_char8_t *fully_qualified_name, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventAssemblyDCEnd_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventAssemblyDCEnd_V1)) + return true; + + uint8_t stack_buffer [94]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&binding_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&assembly_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (fully_qualified_name, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventAssemblyDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +static +bool +write_event_domain_dc_end_v1 ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventAppDomainDCEnd_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventAppDomainDCEnd_V1)) + return true; + + uint8_t stack_buffer [82]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&domain_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (domain_name, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&domain_index, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventAppDomainDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} + +// Mapping FireEtw* CoreClr functions. +#define FireEtwRuntimeInformationDCStart(...) write_runtime_info_dc_start(__VA_ARGS__,NULL,NULL) +#define FireEtwDCEndInit_V1(...) write_event_dc_end_init_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwMethodDCEndILToNativeMap(...) write_event_method_dc_end_il_to_native_map(__VA_ARGS__,NULL,NULL) +#define FireEtwMethodDCEndVerbose_V1(...) write_event_method_dc_end_verbose_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwModuleDCEnd_V2(...) write_event_module_dc_end_v2(__VA_ARGS__,NULL,NULL) +#define FireEtwDomainModuleDCEnd_V1(...) write_event_domain_module_dc_end_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwAssemblyDCEnd_V1(...) write_event_assembly_dc_end_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwAppDomainDCEnd_V1(...) write_event_domain_dc_end_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwDCEndComplete_V1(...) write_event_dc_end_complete_v1(__VA_ARGS__,NULL,NULL) + +// TODO: Add following Mono methods to _EventPipeMonoFuncTable for none static linking scenarios of EventPipe. +// mono_debug_find_method +// mono_debug_free_method_jit_info +// jinfo_get_method +// mono_jit_info_get_generic_sharing_context +// mono_signature_full_name +// mono_type_get_name_full +// mono_stringify_assembly_name +// mono_get_root_domain +// jit_info_table_foreach +// mono_domain_get_assemblies +// g_ptr_array_free + +static +bool +try_fire_method_il_to_native_map_using_debug_info ( + MonoMethod *method, + MonoDomain *domain) +{ + EP_ASSERT (domain != NULL); + + bool result = false; + uint64_t method_id = (uint64_t)method; + + MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, domain) : NULL; + if (debug_info) { + uint32_t stack_buffer [64]; + uint32_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + size_t needed_size = (debug_info->num_line_numbers * sizeof (uint32_t) * 2); + bool fixed_buffer = true; + + if (needed_size > size) + resize_buffer ((uint8_t **)&buffer, &size, offset, (debug_info->num_line_numbers * sizeof (uint32_t) * 2), &fixed_buffer); + + if (needed_size <= size) { + uint32_t *il_offsets = buffer; + uint32_t *native_offsets = buffer + debug_info->num_line_numbers; + + for (int offset_count = 0; offset_count < debug_info->num_line_numbers; ++offset_count) { + il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; + native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; + } + + FireEtwMethodDCEndILToNativeMap ( + method_id, + 0, + 0, + debug_info->num_line_numbers, + il_offsets, + native_offsets, + clr_instance_get_id ()); + + if (!fixed_buffer) + ep_rt_byte_array_free ((uint8_t *)buffer); + + result = true; + } + + mono_debug_free_method_jit_info (debug_info); + } + + return result; +} + +static +void +fire_method_il_to_native_map ( + MonoJitInfo *ji, + MonoDomain *domain) +{ + EP_ASSERT (ji != NULL); + EP_ASSERT (domain != NULL); + + MonoMethod *method = jinfo_get_method (ji); + if (!try_fire_method_il_to_native_map_using_debug_info (method, domain)) { + // No IL offset -> Native offset mapping available. Put all code on IL offset 0. + uint64_t method_id = (uint64_t)method; + uint32_t il_offsets = 0; + uint32_t native_offsets = (uint32_t)ji->code_size; + + FireEtwMethodDCEndILToNativeMap ( + method_id, + 0, + 0, + 1, + &il_offsets, + &native_offsets, + clr_instance_get_id ()); + } +} + +static +void +fire_method_verbose_v1 ( + MonoJitInfo *ji, + MonoDomain *domain) +{ + EP_ASSERT (ji != NULL); + EP_ASSERT (domain != NULL); + + uint64_t method_id = 0; + uint64_t module_id = 0; + uint64_t method_code_start = (uint64_t)ji->code_start; + uint32_t method_code_size = (uint32_t)ji->code_size; + uint32_t method_token = 0; + uint32_t method_flags = 0; + uint8_t kind = MONO_CLASS_DEF; + char *method_namespace = NULL; + const char *method_name = NULL; + char *method_signature = NULL; + + //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. + + MonoMethod *method = jinfo_get_method (ji); + if (method) { + method_id = (uint64_t)method; + method_token = method->token; + + if (mono_jit_info_get_generic_sharing_context (ji)) + method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; + + if (method->dynamic) + method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; + + if (!ji->from_aot && !ji->from_llvm) { + method_flags |= METHOD_FLAGS_JITTED_METHOD; + if (method->wrapper_type != MONO_WRAPPER_NONE) + method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; + } + + if (method->is_generic || method->is_inflated) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + + method_name = method->name; + method_signature = mono_signature_full_name (method->signature); + + if (method->klass) { + module_id = (uint64_t)m_class_get_image (method->klass); + kind = m_class_get_class_kind (method->klass); + if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); + } + } + + FireEtwMethodDCEndVerbose_V1 ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags, + (ep_char8_t *)method_namespace, + (ep_char8_t *)method_name, + (ep_char8_t *)method_signature, + clr_instance_get_id ()); + + g_free (method_namespace); + g_free (method_signature); +} + +static +void +fire_method_events ( + MonoJitInfo *ji, + gpointer user_data) +{ + EP_ASSERT (user_data != NULL); + + if (ji && !ji->is_trampoline && !ji->async) { + fire_method_il_to_native_map (ji, (MonoDomain *)user_data); + fire_method_verbose_v1 (ji, (MonoDomain *)user_data); + } +} + +static +void +fire_assembly_events ( + MonoDomain *domain, + MonoAssembly *assembly) +{ + EP_ASSERT (domain != NULL); + EP_ASSERT (assembly != NULL); + + uint64_t domain_id = (uint64_t)domain; + uint64_t module_id = (uint64_t)assembly->image; + uint64_t assembly_id = (uint64_t)assembly; + + // TODO: Extract all module IL/Native paths and pdb metadata when available. + const char *module_il_path = ""; + const char *module_il_pdb_path = ""; + const char *module_native_path = ""; + const char *module_native_pdb_path = ""; + uint8_t signature [EP_GUID_SIZE] = { 0 }; + uint32_t module_il_pdb_age = 0; + uint32_t module_native_pdb_age = 0; + + uint32_t reserved_flags = 0; + uint64_t binding_id = 0; + + // Native methods are part of JIT table and already emitted. + // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well? + + // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. + uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE; + if (assembly->image) { + if (assembly->image->dynamic) + module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; + if (assembly->image->aot_module) + module_flags |= MODULE_FLAGS_NATIVE_MODULE; + + module_il_path = assembly->image->filename ? assembly->image->filename : ""; + } + + uint32_t assembly_flags = 0; + if (assembly->dynamic) + assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; + + if (assembly->image) { + if (assembly->image->aot_module) + assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; + if (assembly->image->alc) + assembly_flags |= ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY; + } + + FireEtwModuleDCEnd_V2 ( + module_id, + assembly_id, + module_flags, + reserved_flags, + (const ep_char8_t *)module_il_path, + (const ep_char8_t *)module_native_path, + clr_instance_get_id (), + signature, + module_il_pdb_age, + (const ep_char8_t *)module_il_pdb_path, + signature, + module_native_pdb_age, + (const ep_char8_t *)module_native_pdb_path); + + FireEtwDomainModuleDCEnd_V1 ( + module_id, + assembly_id, + domain_id, + module_flags, + reserved_flags, + (const ep_char8_t *)module_il_path, + (const ep_char8_t *)module_native_path, + clr_instance_get_id ()); + + char *assembly_name = mono_stringify_assembly_name (&assembly->aname); + + FireEtwAssemblyDCEnd_V1 ( + assembly_id, + domain_id, + binding_id, + assembly_flags, + (const ep_char8_t *)assembly_name, + clr_instance_get_id ()); + + g_free (assembly_name); +} + +static +void +init_dotnet_runtime_rundown (void) +{ + //TODO: Add callback method to enable/disable more native events getting into EventPipe (when enabled). + EP_ASSERT (EventPipeProviderDotNETRuntimeRundown == NULL); + EventPipeProviderDotNETRuntimeRundown = ep_create_provider (ep_config_get_rundown_provider_name_utf8 (), NULL, NULL, NULL); + + EP_ASSERT (EventPipeEventMethodDCEndVerbose_V1 == NULL); + EventPipeEventMethodDCEndVerbose_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 144, 48, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventDCEndComplete_V1 == NULL); + EventPipeEventDCEndComplete_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 146, 131128, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventDCEndInit_V1 == NULL); + EventPipeEventDCEndInit_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 148, 131128, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventMethodDCEndILToNativeMap == NULL); + EventPipeEventMethodDCEndILToNativeMap = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 150, 131072, 0, EP_EVENT_LEVEL_VERBOSE, true, NULL, 0); + + EP_ASSERT (EventPipeEventDomainModuleDCEnd_V1 == NULL); + EventPipeEventDomainModuleDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 152, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventModuleDCEnd_V2 == NULL); + EventPipeEventModuleDCEnd_V2 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 154, 536870920, 2, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventAssemblyDCEnd_V1 == NULL); + EventPipeEventAssemblyDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 156, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventAppDomainDCEnd_V1 == NULL); + EventPipeEventAppDomainDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 158, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventRuntimeInformationDCStart == NULL); + EventPipeEventRuntimeInformationDCStart = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 187, 0, 0, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); +} + +void +ep_rt_mono_init_providers_and_events (void) +{ + init_dotnet_runtime_rundown (); +} + +void +ep_rt_mono_fini_providers_and_events (void) +{ + // dotnet/runtime: issue 12775: EventPipe shutdown race conditions + // Deallocating providers/events here might cause AV if a WriteEvent + // was to occur. Thus, we are not doing this cleanup. + + // ep_delete_provider (EventPipeProviderDotNETRuntimeRundown); +} + +void +ep_rt_mono_execute_rundown (void) +{ + const uint8_t object_guid [EP_GUID_SIZE] = { 0 }; + const uint16_t runtime_product_qfe_version = 0; + const uint32_t startup_flags = 0; + const uint8_t startup_mode = 0; + const ep_char8_t *command_line = ""; + const ep_char8_t *runtime_dll_path = ""; + + // TODO: Add coreclr dll module file name. + FireEtwRuntimeInformationDCStart ( + clr_instance_get_id (), + RUNTIME_SKU_CORECLR, + RuntimeProductMajorVersion, + RuntimeProductMinorVersion, + RuntimeProductPatchVersion, + runtime_product_qfe_version, + RuntimeFileMajorVersion, + RuntimeFileMajorVersion, + RuntimeFileBuildVersion, + RuntimeFileRevisionVersion, + startup_mode, + startup_flags, + command_line, + object_guid, + runtime_dll_path); + + FireEtwDCEndInit_V1 (clr_instance_get_id ()); + + // Under netcore we only have root domain. + MonoDomain *root_domain = mono_get_root_domain (); + if (root_domain) { + uint64_t domain_id = (uint64_t)root_domain; + + // Iterate all functions in use (both JIT and AOT). + jit_info_table_foreach (root_domain, fire_method_events, root_domain); + + // Iterate all assemblies in domain. + GPtrArray *assemblies = mono_domain_get_assemblies (root_domain, FALSE); + if (assemblies) { + for (int i = 0; i < assemblies->len; ++i) { + MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i); + if (assembly) + fire_assembly_events (root_domain, assembly); + } + g_ptr_array_free (assemblies, TRUE); + } + + uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN; + const ep_char8_t *domain_name = (const ep_char8_t *)(root_domain->friendly_name ? root_domain->friendly_name : ""); + uint32_t domain_index = 1; + + FireEtwAppDomainDCEnd_V1 ( + domain_id, + domain_flags, + domain_name, + domain_index, + clr_instance_get_id ()); + } + + FireEtwDCEndComplete_V1 (clr_instance_get_id ()); +} + #endif /* ENABLE_PERFTRACING */ MONO_EMPTY_SOURCE_FILE(eventpipe_rt_mono); diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index 7a6df3883e68ee..27645fa760fbcf 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -421,6 +421,15 @@ ep_rt_mono_system_timestamp_get (void); void ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array); +void +ep_rt_mono_init_providers_and_events (void); + +void +ep_rt_mono_fini_providers_and_events (void); + +void +ep_rt_mono_execute_rundown (void); + #ifndef EP_RT_MONO_USE_STATIC_RUNTIME static inline @@ -866,7 +875,7 @@ inline void ep_rt_init_providers_and_events (void) { - ; + ep_rt_mono_init_providers_and_events (); } static @@ -1036,6 +1045,19 @@ ep_rt_config_value_get_use_portable_thread_pool (void) return true; } +static +inline +uint32_t +ep_rt_config_value_get_rundown (void) +{ + uint32_t value_uint32_t = 1; + gchar *value = g_getenv ("COMPlus_EventPipeRundown"); + if (value) + value_uint32_t = (uint32_t)atoi (value); + g_free (value); + return value_uint32_t; +} + /* * EventPipeSampleProfiler. */ @@ -1313,7 +1335,11 @@ inline void ep_rt_execute_rundown (void) { - //TODO: Implement. + if (ep_rt_config_value_get_rundown () > 0) { + // Ask the runtime to emit rundown events. + if (/*is_running &&*/ !ep_rt_process_shutdown ()) + ep_rt_mono_execute_rundown (); + } } /* diff --git a/src/mono/mono/metadata/domain-internals.h b/src/mono/mono/metadata/domain-internals.h index 90f72eb3759dcb..66b316331fbaf7 100644 --- a/src/mono/mono/metadata/domain-internals.h +++ b/src/mono/mono/metadata/domain-internals.h @@ -665,6 +665,11 @@ void mono_assembly_cleanup_domain_bindings (guint32 domain_id); MonoJitInfo* mono_jit_info_table_find_internal (MonoDomain *domain, gpointer addr, gboolean try_aot, gboolean allow_trampolines); +typedef void (*MonoJitInfoFunc) (MonoJitInfo *ji, gpointer user_data); + +void +jit_info_table_foreach (MonoDomain *domain, MonoJitInfoFunc func, gpointer user_data); + void mono_enable_debug_domain_unload (gboolean enable); void diff --git a/src/mono/mono/metadata/jit-info.c b/src/mono/mono/metadata/jit-info.c index 8410edbb3319b9..3fee40d7fac522 100644 --- a/src/mono/mono/metadata/jit-info.c +++ b/src/mono/mono/metadata/jit-info.c @@ -337,6 +337,33 @@ mono_jit_info_table_find (MonoDomain *domain, gpointer addr) return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE); } +void +jit_info_table_foreach (MonoDomain *domain, MonoJitInfoFunc func, gpointer user_data) +{ + MonoJitInfoTable *table; + MonoJitInfo *ji; + MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); + + table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX); + if (table) { + for (int chunk_index = 0; chunk_index < table->num_chunks; ++chunk_index) { + MonoJitInfoTableChunk *chunk = table->chunks [chunk_index]; + for (int jit_info_index = 0; jit_info_index < chunk->num_elements; ++jit_info_index) { + + ji = (MonoJitInfo *)mono_get_hazardous_pointer ((gpointer volatile*)&chunk->data [jit_info_index], hp, JIT_INFO_HAZARD_INDEX); + + if (func && !IS_JIT_INFO_TOMBSTONE (ji)) + func (ji, user_data); + + mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX); + } + } + } + + if (hp) + mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX); +} + static G_GNUC_UNUSED void jit_info_table_check (MonoJitInfoTable *table) { diff --git a/src/native/eventpipe/ds-process-protocol.c b/src/native/eventpipe/ds-process-protocol.c index ffb705d046f188..d8acf030124c5c 100644 --- a/src/native/eventpipe/ds-process-protocol.c +++ b/src/native/eventpipe/ds-process-protocol.c @@ -174,7 +174,7 @@ ds_process_info_payload_init ( payload->process_id = process_id; if (runtime_cookie) - memcpy (&payload->runtime_cookie, runtime_cookie, EP_ACTIVITY_ID_SIZE); + memcpy (&payload->runtime_cookie, runtime_cookie, EP_GUID_SIZE); return payload; } diff --git a/src/native/eventpipe/ds-process-protocol.h b/src/native/eventpipe/ds-process-protocol.h index 520819016ed5aa..62c7658a27cd89 100644 --- a/src/native/eventpipe/ds-process-protocol.h +++ b/src/native/eventpipe/ds-process-protocol.h @@ -37,7 +37,7 @@ struct _DiagnosticsProcessInfoPayload_Internal { const ep_char16_t *command_line; const ep_char16_t *os; const ep_char16_t *arch; - uint8_t runtime_cookie [EP_ACTIVITY_ID_SIZE]; + uint8_t runtime_cookie [EP_GUID_SIZE]; }; #if !defined(DS_INLINE_GETTER_SETTER) && !defined(DS_IMPL_PROCESS_PROTOCOL_GETTER_SETTER) diff --git a/src/native/eventpipe/ds-profiler-protocol.h b/src/native/eventpipe/ds-profiler-protocol.h index 2f2b652f59f700..004a44aa474440 100644 --- a/src/native/eventpipe/ds-profiler-protocol.h +++ b/src/native/eventpipe/ds-profiler-protocol.h @@ -33,7 +33,7 @@ struct _DiagnosticsAttachProfilerCommandPayload_Internal { // ulong - status uint32_t attach_timeout; - uint8_t profiler_guid [EP_ACTIVITY_ID_SIZE]; + uint8_t profiler_guid [EP_GUID_SIZE]; const ep_char16_t *profiler_path; uint32_t client_data_len; uint8_t *client_data; diff --git a/src/native/eventpipe/ds-protocol.c b/src/native/eventpipe/ds-protocol.c index 26771d4affc84d..606376449ad9ba 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_ACTIVITY_ID_SIZE] = { 0 }; +static uint8_t _ds_ipc_advertise_cooike_v1 [EP_GUID_SIZE] = { 0 }; /* * Forward declares of all static functions. @@ -72,7 +72,7 @@ ds_ipc_advertise_cookie_v1_get (void) void ds_ipc_advertise_cookie_v1_init (void) { - ep_rt_create_activity_id ((uint8_t *)&_ds_ipc_advertise_cooike_v1, EP_ACTIVITY_ID_SIZE); + ep_rt_create_activity_id ((uint8_t *)&_ds_ipc_advertise_cooike_v1, EP_GUID_SIZE); } /** @@ -104,7 +104,7 @@ ds_icp_advertise_v1_send (DiagnosticsIpcStream *stream) buffer++; // fills buffer[1] and buffer[2] - memcpy (buffer, cookie, EP_ACTIVITY_ID_SIZE); + memcpy (buffer, cookie, EP_GUID_SIZE); buffer +=2; memcpy (buffer, &pid, sizeof (uint64_t)); diff --git a/src/native/eventpipe/ep-types.h b/src/native/eventpipe/ep-types.h index 0ebe90232efeb1..0c91757fcfbe95 100644 --- a/src/native/eventpipe/ep-types.h +++ b/src/native/eventpipe/ep-types.h @@ -62,7 +62,9 @@ typedef struct _StreamWriterVtable StreamWriterVtable; #define EP_MAX_NUMBER_OF_SESSIONS 64 -#define EP_ACTIVITY_ID_SIZE 16 +#define EP_GUID_SIZE 16 + +#define EP_ACTIVITY_ID_SIZE EP_GUID_SIZE #define EP_MAX_STACK_DEPTH 100 From c934ef4ce4a63ae93b9e6c6be248f5fe84227547 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 22 Jan 2021 16:33:59 +0100 Subject: [PATCH 2/8] Enable additional runtime tests passing after emitting rundown events. --- src/tests/issues.targets | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index e5a311bfafca01..15751f0880f502 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1838,15 +1838,9 @@ needs triage - - needs triage - needs triage - - needs triage - needs triage @@ -1871,15 +1865,9 @@ needs triage - - needs triage - needs triage - - needs triage - needs triage From 340d61c038d6d32ed37e7196a8a5e0b513f91dd2 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Mon, 25 Jan 2021 11:54:29 +0100 Subject: [PATCH 3/8] Implement custom alloc for utf8/utf16 conversion. Reduce heap allocations for all strings emitted in rundown. Support buffer in place conversions. --- src/mono/mono/eglib/giconv.c | 60 +++++++++++++++++++++++----- src/mono/mono/eglib/glib.h | 29 +++++++++++++- src/mono/mono/eglib/gmodule-win32.c | 10 +++-- src/mono/mono/eventpipe/ep-rt-mono.c | 46 ++++++++++----------- src/tests/issues.targets | 3 ++ 5 files changed, 111 insertions(+), 37 deletions(-) diff --git a/src/mono/mono/eglib/giconv.c b/src/mono/mono/eglib/giconv.c index 8223d4a62b9fec..c502e8c71bb4dd 100644 --- a/src/mono/mono/eglib/giconv.c +++ b/src/mono/mono/eglib/giconv.c @@ -831,7 +831,7 @@ g_utf8_to_ucs4_fast (const gchar *str, glong len, glong *items_written) } static gunichar2 * -eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong *items_written, gboolean include_nuls, gboolean replace_invalid_codepoints, GError **err) +eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong *items_written, gboolean include_nuls, gboolean replace_invalid_codepoints, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { gunichar2 *outbuf, *outptr; size_t outlen = 0; @@ -881,7 +881,16 @@ eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong if (items_written) *items_written = outlen; - outptr = outbuf = g_malloc ((outlen + 1) * sizeof (gunichar2)); + if (G_LIKELY (!custom_alloc_func)) + outptr = outbuf = g_malloc ((outlen + 1) * sizeof (gunichar2)); + else + outptr = outbuf = custom_alloc_func ((outlen + 1) * sizeof (gunichar2), custom_alloc_data); + + if (G_UNLIKELY (custom_alloc_func && !outbuf)) { + mono_set_errno (ENOMEM); + goto error; + } + inptr = (char *) str; inleft = len; @@ -908,8 +917,11 @@ eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong return outbuf; - error: - if (errno == EILSEQ) { +error: + if (errno == ENOMEM) { + g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_ALLOC_FAILED, + "Allocation failed."); + } else if (errno == EILSEQ) { g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, "Illegal byte sequence encounted in the input."); } else if (items_read) { @@ -931,19 +943,25 @@ eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong gunichar2 * g_utf8_to_utf16 (const gchar *str, glong len, glong *items_read, glong *items_written, GError **err) { - return eg_utf8_to_utf16_general (str, len, items_read, items_written, FALSE, FALSE, err); + return eg_utf8_to_utf16_general (str, len, items_read, items_written, FALSE, FALSE, NULL, NULL, err); +} + +gunichar2 * +g_utf8_to_utf16_custom_alloc (const gchar *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator cusotm_alloc_func, gpointer custom_alloc_data, GError **err) +{ + return eg_utf8_to_utf16_general (str, len, items_read, items_written, FALSE, FALSE, cusotm_alloc_func, custom_alloc_data, err); } gunichar2 * eg_utf8_to_utf16_with_nuls (const gchar *str, glong len, glong *items_read, glong *items_written, GError **err) { - return eg_utf8_to_utf16_general (str, len, items_read, items_written, TRUE, FALSE, err); + return eg_utf8_to_utf16_general (str, len, items_read, items_written, TRUE, FALSE, NULL, NULL, err); } gunichar2 * eg_wtf8_to_utf16 (const gchar *str, glong len, glong *items_read, glong *items_written, GError **err) { - return eg_utf8_to_utf16_general (str, len, items_read, items_written, TRUE, TRUE, err); + return eg_utf8_to_utf16_general (str, len, items_read, items_written, TRUE, TRUE, NULL, NULL, err); } gunichar * @@ -1018,8 +1036,9 @@ g_utf8_to_ucs4 (const gchar *str, glong len, glong *items_read, glong *items_wri return outbuf; } +static gchar * -g_utf16_to_utf8 (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GError **err) +g_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { char *inptr, *outbuf, *outptr; size_t outlen = 0; @@ -1077,8 +1096,19 @@ g_utf16_to_utf8 (const gunichar2 *str, glong len, glong *items_read, glong *item if (items_written) *items_written = outlen; + + if (G_LIKELY (!custom_alloc_func)) + outptr = outbuf = g_malloc (outlen + 1); + else + outptr = outbuf = custom_alloc_func (outlen + 1, custom_alloc_data); + + if (G_UNLIKELY (custom_alloc_func && !outbuf)) { + g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_ALLOC_FAILED, "Allocation failed."); + if (items_written) + *items_written = 0; + return NULL; + } - outptr = outbuf = g_malloc (outlen + 1); inptr = (char *) str; inleft = len * 2; @@ -1098,6 +1128,18 @@ g_utf16_to_utf8 (const gunichar2 *str, glong len, glong *items_read, glong *item return outbuf; } +gchar * +g_utf16_to_utf8 (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GError **err) +{ + return g_utf16_to_utf8_general (str, len, items_read, items_written, NULL, NULL, err); +} + +gchar * +g_utf16_to_utf8_custom_alloc (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) +{ + return g_utf16_to_utf8_general (str, len, items_read, items_written, custom_alloc_func, custom_alloc_data, err); +} + gunichar * g_utf16_to_ucs4 (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GError **err) { diff --git a/src/mono/mono/eglib/glib.h b/src/mono/mono/eglib/glib.h index 019c3b41d6cec4..d58296660d3f55 100644 --- a/src/mono/mono/eglib/glib.h +++ b/src/mono/mono/eglib/glib.h @@ -1004,7 +1004,8 @@ typedef enum { G_CONVERT_ERROR_FAILED, G_CONVERT_ERROR_PARTIAL_INPUT, G_CONVERT_ERROR_BAD_URI, - G_CONVERT_ERROR_NOT_ABSOLUTE_PATH + G_CONVERT_ERROR_NOT_ABSOLUTE_PATH, + G_CONVERT_ERROR_ALLOC_FAILED } GConvertError; gchar *g_utf8_strup (const gchar *str, gssize len); @@ -1031,6 +1032,32 @@ size_t g_utf16_len (const gunichar2 *); #define u16to8(str) g_utf16_to_utf8(str, (glong)strlen(str), NULL, NULL, NULL) #endif +typedef gpointer (*GConvertCustomAllocator) (gsize req_size, gpointer custom_alloc_data); + +typedef struct { + gpointer buffer; + gsize buffer_size; + gsize req_buffer_size; +} GConvertDefaultCustomAllocatorData; + +static +gpointer +g_converter_default_custom_allocator_func (gsize req_size, gpointer custom_alloc_data) +{ + GConvertDefaultCustomAllocatorData *default_custom_alloc_data = (GConvertDefaultCustomAllocatorData *)custom_alloc_data; + if (!default_custom_alloc_data) + return NULL; + + default_custom_alloc_data->req_buffer_size = req_size; + if (req_size > default_custom_alloc_data->buffer_size) + return NULL; + + return default_custom_alloc_data->buffer; +} + +gunichar2 *g_utf8_to_utf16_custom_alloc (const gchar *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err); +gchar *g_utf16_to_utf8_custom_alloc (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err); + /* * Path */ diff --git a/src/mono/mono/eglib/gmodule-win32.c b/src/mono/mono/eglib/gmodule-win32.c index 9b628b21e309fa..0a20210f206697 100644 --- a/src/mono/mono/eglib/gmodule-win32.c +++ b/src/mono/mono/eglib/gmodule-win32.c @@ -163,17 +163,21 @@ g_module_address (void *addr, char *file_name, size_t file_name_len, * this being an exception. */ BOOL ret = GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)addr, &module); - if (ret) + if (!ret) return FALSE; if (file_name != NULL && file_name_len >= 1) { /* sigh, non-const. AIX for POSIX is the same way. */ WCHAR fname [MAX_PATH]; DWORD bytes = GetModuleFileNameW (module, fname, G_N_ELEMENTS (fname)); - /* XXX: check for ERROR_INSUFFICIENT_BUFFER? */ if (bytes) { /* Convert back to UTF-8 from wide for runtime */ - *file_name = '\0'; /* XXX */ + GConvertDefaultCustomAllocatorData custom_alloc_data; + custom_alloc_data.buffer = file_name; + custom_alloc_data.buffer_size = file_name_len; + custom_alloc_data.req_buffer_size = 0; + if (!g_utf16_to_utf8_custom_alloc (fname, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL)) + *file_name = '\0'; } else { *file_name = '\0'; } diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index bf8c9844280023..d0e66bc8df03a2 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include ep_rt_spin_lock_handle_t _ep_rt_mono_config_lock = {0}; @@ -610,30 +612,24 @@ write_buffer_string_utf8_t ( if (!value) return true; - bool result = false; - ep_char16_t *value_utf16 = NULL; - - // TODO: Implement conversion into output buffer, eliminate heap allocation. - value_utf16 = ep_rt_utf8_to_utf16_string (value, -1); - ep_raise_error_if_nok (value_utf16 != NULL); - - size_t value_utf16_size; - value_utf16_size = (ep_rt_utf16_string_len (value_utf16) + 1) * sizeof (ep_char16_t); - - if ((value_utf16_size + *offset) > *size) - ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + value_utf16_size, fixed_buffer)); - - memcpy (*buffer + *offset, value_utf16, value_utf16_size); - *offset += value_utf16_size; - - result = true; + GConvertDefaultCustomAllocatorData custom_alloc_data; + custom_alloc_data.buffer = *buffer + *offset; + custom_alloc_data.buffer_size = *size - *offset; + custom_alloc_data.req_buffer_size = 0; + + if (!g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL)) { + ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + custom_alloc_data.req_buffer_size, fixed_buffer)); + custom_alloc_data.buffer = *buffer + *offset; + custom_alloc_data.buffer_size = *size - *offset; + custom_alloc_data.req_buffer_size = 0; + ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL)); + } -ep_on_exit: - ep_rt_utf16_string_free (value_utf16); - return result; + *offset += custom_alloc_data.req_buffer_size; + return true; ep_on_error: - ep_exit_error_handler (); + return false; } static @@ -1461,14 +1457,16 @@ ep_rt_mono_fini_providers_and_events (void) void ep_rt_mono_execute_rundown (void) { + ep_char8_t runtime_module_path [256]; const uint8_t object_guid [EP_GUID_SIZE] = { 0 }; const uint16_t runtime_product_qfe_version = 0; const uint32_t startup_flags = 0; const uint8_t startup_mode = 0; const ep_char8_t *command_line = ""; - const ep_char8_t *runtime_dll_path = ""; - // TODO: Add coreclr dll module file name. + if (!g_module_address ((void *)ep_rt_mono_execute_rundown, runtime_module_path, sizeof (runtime_module_path), NULL, NULL, 0, NULL)) + runtime_module_path [0] = '\0'; + FireEtwRuntimeInformationDCStart ( clr_instance_get_id (), RUNTIME_SKU_CORECLR, @@ -1484,7 +1482,7 @@ ep_rt_mono_execute_rundown (void) startup_flags, command_line, object_guid, - runtime_dll_path); + runtime_module_path); FireEtwDCEndInit_V1 (clr_instance_get_id ()); diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 15751f0880f502..e6b06778ce5b3e 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1868,6 +1868,9 @@ needs triage + + needs triage + needs triage From 8d448d24ff5caf0b6c13f092267757992369e257 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Tue, 26 Jan 2021 10:23:31 +0100 Subject: [PATCH 4/8] Move assembly/method rundown iteration into runtime source. --- src/mono/mono/eventpipe/ep-rt-mono.c | 426 +++++++---------------- src/mono/mono/eventpipe/ep-rt-mono.h | 105 +++--- src/mono/mono/metadata/icall-eventpipe.c | 366 ++++++++++++++++++- 3 files changed, 540 insertions(+), 357 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index d0e66bc8df03a2..9ea4dc462f7392 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -7,11 +7,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include @@ -288,23 +283,6 @@ ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) // Rundown flags. #define RUNTIME_SKU_CORECLR 0x2 -#define METHOD_FLAGS_DYNAMIC_METHOD 0x1 -#define METHOD_FLAGS_GENERIC_METHOD 0x2 -#define METHOD_FLAGS_SHARED_GENERIC_METHOD 0x4 -#define METHOD_FLAGS_JITTED_METHOD 0x8 -#define METHOD_FLAGS_JITTED_HELPER_METHOD 0x10 - -#define MODULE_FLAGS_NATIVE_MODULE 0x2 -#define MODULE_FLAGS_DYNAMIC_MODULE 0x4 -#define MODULE_FLAGS_MANIFEST_MODULE 0x8 - -#define ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY 0x2 -#define ASSEMBLY_FLAGS_NATIVE_ASSEMBLY 0x4 -#define ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY 0x8 - -#define DOMAIN_FLAGS_DEFAULT_DOMAIN 0x1 -#define DOMAIN_FLAGS_EXECUTABLE_DOMAIN 0x2 - // Rundown events. EventPipeProvider *EventPipeProviderDotNETRuntimeRundown = NULL; EventPipeEvent *EventPipeEventMethodDCEndVerbose_V1 = NULL; @@ -490,33 +468,50 @@ write_event_domain_dc_end_v1 ( static bool -try_fire_method_il_to_native_map_using_debug_info ( - MonoMethod *method, - MonoDomain *domain); - -static -void -fire_method_il_to_native_map ( - MonoJitInfo *ji, - MonoDomain *domain); - -static -void -fire_method_verbose_v1 ( - MonoJitInfo *ji, - MonoDomain *domain); +fire_method_rundown_events_func ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + void *user_data); static -void -fire_method_events ( - MonoJitInfo *ji, - gpointer user_data); +bool +fire_assembly_rundown_events_func ( + const uint64_t domain_id, + const uint64_t assembly_id, + const uint32_t assembly_flags, + const uint32_t binding_id, + const ep_char8_t *assembly_name, + const uint64_t module_id, + const uint32_t module_flags, + const uint32_t reserved_flags, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + void *user_data); static -void -fire_assembly_events ( - MonoDomain *domain, - MonoAssembly *assembly); +bool +fire_domain_rundown_events_func ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + void *user_data); static void @@ -622,7 +617,7 @@ write_buffer_string_utf8_t ( custom_alloc_data.buffer = *buffer + *offset; custom_alloc_data.buffer_size = *size - *offset; custom_alloc_data.req_buffer_size = 0; - ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL)); + ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL) != NULL); } *offset += custom_alloc_data.req_buffer_size; @@ -1137,247 +1132,82 @@ write_event_domain_dc_end_v1 ( #define FireEtwAppDomainDCEnd_V1(...) write_event_domain_dc_end_v1(__VA_ARGS__,NULL,NULL) #define FireEtwDCEndComplete_V1(...) write_event_dc_end_complete_v1(__VA_ARGS__,NULL,NULL) -// TODO: Add following Mono methods to _EventPipeMonoFuncTable for none static linking scenarios of EventPipe. -// mono_debug_find_method -// mono_debug_free_method_jit_info -// jinfo_get_method -// mono_jit_info_get_generic_sharing_context -// mono_signature_full_name -// mono_type_get_name_full -// mono_stringify_assembly_name -// mono_get_root_domain -// jit_info_table_foreach -// mono_domain_get_assemblies -// g_ptr_array_free - static bool -try_fire_method_il_to_native_map_using_debug_info ( - MonoMethod *method, - MonoDomain *domain) -{ - EP_ASSERT (domain != NULL); - - bool result = false; - uint64_t method_id = (uint64_t)method; - - MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, domain) : NULL; - if (debug_info) { - uint32_t stack_buffer [64]; - uint32_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - size_t needed_size = (debug_info->num_line_numbers * sizeof (uint32_t) * 2); - bool fixed_buffer = true; - - if (needed_size > size) - resize_buffer ((uint8_t **)&buffer, &size, offset, (debug_info->num_line_numbers * sizeof (uint32_t) * 2), &fixed_buffer); - - if (needed_size <= size) { - uint32_t *il_offsets = buffer; - uint32_t *native_offsets = buffer + debug_info->num_line_numbers; - - for (int offset_count = 0; offset_count < debug_info->num_line_numbers; ++offset_count) { - il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; - native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; - } - - FireEtwMethodDCEndILToNativeMap ( - method_id, - 0, - 0, - debug_info->num_line_numbers, - il_offsets, - native_offsets, - clr_instance_get_id ()); - - if (!fixed_buffer) - ep_rt_byte_array_free ((uint8_t *)buffer); - - result = true; - } - - mono_debug_free_method_jit_info (debug_info); - } - - return result; -} - -static -void -fire_method_il_to_native_map ( - MonoJitInfo *ji, - MonoDomain *domain) -{ - EP_ASSERT (ji != NULL); - EP_ASSERT (domain != NULL); - - MonoMethod *method = jinfo_get_method (ji); - if (!try_fire_method_il_to_native_map_using_debug_info (method, domain)) { - // No IL offset -> Native offset mapping available. Put all code on IL offset 0. - uint64_t method_id = (uint64_t)method; - uint32_t il_offsets = 0; - uint32_t native_offsets = (uint32_t)ji->code_size; - - FireEtwMethodDCEndILToNativeMap ( - method_id, - 0, - 0, - 1, - &il_offsets, - &native_offsets, - clr_instance_get_id ()); - } -} - -static -void -fire_method_verbose_v1 ( - MonoJitInfo *ji, - MonoDomain *domain) +fire_method_rundown_events_func ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + void *user_data) { - EP_ASSERT (ji != NULL); - EP_ASSERT (domain != NULL); - - uint64_t method_id = 0; - uint64_t module_id = 0; - uint64_t method_code_start = (uint64_t)ji->code_start; - uint32_t method_code_size = (uint32_t)ji->code_size; - uint32_t method_token = 0; - uint32_t method_flags = 0; - uint8_t kind = MONO_CLASS_DEF; - char *method_namespace = NULL; - const char *method_name = NULL; - char *method_signature = NULL; - - //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. - - MonoMethod *method = jinfo_get_method (ji); - if (method) { - method_id = (uint64_t)method; - method_token = method->token; - - if (mono_jit_info_get_generic_sharing_context (ji)) - method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; - - if (method->dynamic) - method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; - - if (!ji->from_aot && !ji->from_llvm) { - method_flags |= METHOD_FLAGS_JITTED_METHOD; - if (method->wrapper_type != MONO_WRAPPER_NONE) - method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; - } - - if (method->is_generic || method->is_inflated) - method_flags |= METHOD_FLAGS_GENERIC_METHOD; - - method_name = method->name; - method_signature = mono_signature_full_name (method->signature); - - if (method->klass) { - module_id = (uint64_t)m_class_get_image (method->klass); - kind = m_class_get_class_kind (method->klass); - if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) - method_flags |= METHOD_FLAGS_GENERIC_METHOD; - method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); - } - } + FireEtwMethodDCEndILToNativeMap ( + method_id, + 0, + 0, + count_of_map_entries, + il_offsets, + native_offsets, + clr_instance_get_id ()); FireEtwMethodDCEndVerbose_V1 ( method_id, module_id, - method_code_start, - method_code_size, + method_start_address, + method_size, method_token, method_flags, - (ep_char8_t *)method_namespace, - (ep_char8_t *)method_name, - (ep_char8_t *)method_signature, + method_namespace, + method_name, + method_signature, clr_instance_get_id ()); - g_free (method_namespace); - g_free (method_signature); -} - -static -void -fire_method_events ( - MonoJitInfo *ji, - gpointer user_data) -{ - EP_ASSERT (user_data != NULL); - - if (ji && !ji->is_trampoline && !ji->async) { - fire_method_il_to_native_map (ji, (MonoDomain *)user_data); - fire_method_verbose_v1 (ji, (MonoDomain *)user_data); - } + return true; } static -void -fire_assembly_events ( - MonoDomain *domain, - MonoAssembly *assembly) +bool +fire_assembly_rundown_events_func ( + const uint64_t domain_id, + const uint64_t assembly_id, + const uint32_t assembly_flags, + const uint32_t binding_id, + const ep_char8_t *assembly_name, + const uint64_t module_id, + const uint32_t module_flags, + const uint32_t reserved_flags, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + void *user_data) { - EP_ASSERT (domain != NULL); - EP_ASSERT (assembly != NULL); - - uint64_t domain_id = (uint64_t)domain; - uint64_t module_id = (uint64_t)assembly->image; - uint64_t assembly_id = (uint64_t)assembly; - - // TODO: Extract all module IL/Native paths and pdb metadata when available. - const char *module_il_path = ""; - const char *module_il_pdb_path = ""; - const char *module_native_path = ""; - const char *module_native_pdb_path = ""; - uint8_t signature [EP_GUID_SIZE] = { 0 }; - uint32_t module_il_pdb_age = 0; - uint32_t module_native_pdb_age = 0; - - uint32_t reserved_flags = 0; - uint64_t binding_id = 0; - - // Native methods are part of JIT table and already emitted. - // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well? - - // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. - uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE; - if (assembly->image) { - if (assembly->image->dynamic) - module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; - if (assembly->image->aot_module) - module_flags |= MODULE_FLAGS_NATIVE_MODULE; - - module_il_path = assembly->image->filename ? assembly->image->filename : ""; - } - - uint32_t assembly_flags = 0; - if (assembly->dynamic) - assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; - - if (assembly->image) { - if (assembly->image->aot_module) - assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; - if (assembly->image->alc) - assembly_flags |= ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY; - } - FireEtwModuleDCEnd_V2 ( module_id, assembly_id, module_flags, reserved_flags, - (const ep_char8_t *)module_il_path, - (const ep_char8_t *)module_native_path, + module_il_path, + module_native_path, clr_instance_get_id (), - signature, - module_il_pdb_age, - (const ep_char8_t *)module_il_pdb_path, - signature, - module_native_pdb_age, - (const ep_char8_t *)module_native_pdb_path); + managed_pdb_signature, + managed_pdb_age, + managed_pdb_build_path, + native_pdb_signature, + native_pdb_age, + native_pdb_build_path); FireEtwDomainModuleDCEnd_V1 ( module_id, @@ -1385,21 +1215,36 @@ fire_assembly_events ( domain_id, module_flags, reserved_flags, - (const ep_char8_t *)module_il_path, - (const ep_char8_t *)module_native_path, + module_il_path, + module_native_path, clr_instance_get_id ()); - char *assembly_name = mono_stringify_assembly_name (&assembly->aname); - FireEtwAssemblyDCEnd_V1 ( assembly_id, domain_id, binding_id, assembly_flags, - (const ep_char8_t *)assembly_name, + assembly_name, clr_instance_get_id ()); - g_free (assembly_name); + return true; +} + +static +bool +fire_domain_rundown_events_func ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + void *user_data) +{ + return FireEtwAppDomainDCEnd_V1 ( + domain_id, + domain_flags, + domain_name, + domain_index, + clr_instance_get_id ()); } static @@ -1464,7 +1309,7 @@ ep_rt_mono_execute_rundown (void) const uint8_t startup_mode = 0; const ep_char8_t *command_line = ""; - if (!g_module_address ((void *)ep_rt_mono_execute_rundown, runtime_module_path, sizeof (runtime_module_path), NULL, NULL, 0, NULL)) + if (!g_module_address ((void *)mono_init, runtime_module_path, sizeof (runtime_module_path), NULL, NULL, 0, NULL)) runtime_module_path [0] = '\0'; FireEtwRuntimeInformationDCStart ( @@ -1486,36 +1331,11 @@ ep_rt_mono_execute_rundown (void) FireEtwDCEndInit_V1 (clr_instance_get_id ()); - // Under netcore we only have root domain. - MonoDomain *root_domain = mono_get_root_domain (); - if (root_domain) { - uint64_t domain_id = (uint64_t)root_domain; - - // Iterate all functions in use (both JIT and AOT). - jit_info_table_foreach (root_domain, fire_method_events, root_domain); - - // Iterate all assemblies in domain. - GPtrArray *assemblies = mono_domain_get_assemblies (root_domain, FALSE); - if (assemblies) { - for (int i = 0; i < assemblies->len; ++i) { - MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i); - if (assembly) - fire_assembly_events (root_domain, assembly); - } - g_ptr_array_free (assemblies, TRUE); - } - - uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN; - const ep_char8_t *domain_name = (const ep_char8_t *)(root_domain->friendly_name ? root_domain->friendly_name : ""); - uint32_t domain_index = 1; - - FireEtwAppDomainDCEnd_V1 ( - domain_id, - domain_flags, - domain_name, - domain_index, - clr_instance_get_id ()); - } + EP_ASSERT (_ep_rt_mono_func_table.ep_rt_mono_execute_rundown != NULL); + _ep_rt_mono_func_table.ep_rt_mono_execute_rundown ( + fire_domain_rundown_events_func, + fire_assembly_rundown_events_func, + fire_method_rundown_events_func); FireEtwDCEndComplete_V1 (clr_instance_get_id ()); } diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index 27645fa760fbcf..f2b020d5af5b22 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -347,6 +347,54 @@ prefix_name ## _rt_ ## type_name ## _ ## func_name #define EP_RT_DEFINE_HASH_MAP_ITERATOR(hash_map_name, hash_map_type, iterator_type, key_type, value_type) \ EP_RT_DEFINE_HASH_MAP_ITERATOR_PREFIX(ep, hash_map_name, hash_map_type, iterator_type, key_type, value_type) +// Rundown callbacks. +typedef +bool +(*ep_rt_mono_fire_method_rundown_events_func)( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + void *user_data); + +typedef +bool +(*ep_rt_mono_fire_assembly_rundown_events_func)( + const uint64_t domain_id, + const uint64_t assembly_id, + const uint32_t assembly_flags, + const uint32_t binding_id, + const ep_char8_t *assembly_name, + const uint64_t module_id, + const uint32_t module_flags, + const uint32_t reserved_flags, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + void *user_data); + +typedef +bool +(*ep_rt_mono_fire_domain_rundown_events_func)( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + void *user_data); + typedef EventPipeThreadHolder * (*ep_rt_thread_holder_alloc_func)(void); typedef void (*ep_rt_thread_holder_free_func)(EventPipeThreadHolder *thread_holder); @@ -376,6 +424,7 @@ typedef gpointer (*ep_rt_mono_thread_attach_func)(gboolean); typedef void (*ep_rt_mono_thread_detach_func)(void); typedef char* (*ep_rt_mono_get_os_cmd_line_func)(void); typedef char* (*ep_rt_mono_get_managed_cmd_line_func)(void); +typedef gboolean (*ep_rt_mono_execute_rundown_func)(ep_rt_mono_fire_domain_rundown_events_func domain_events_func, ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, ep_rt_mono_fire_method_rundown_events_func methods_events_func); typedef struct _EventPipeMonoFuncTable { ep_rt_mono_process_current_pid_func ep_rt_mono_process_current_pid; @@ -404,6 +453,7 @@ typedef struct _EventPipeMonoFuncTable { ep_rt_mono_thread_detach_func ep_rt_mono_thread_detach; ep_rt_mono_get_os_cmd_line_func ep_rt_mono_get_os_cmd_line; ep_rt_mono_get_managed_cmd_line_func ep_rt_mono_get_managed_cmd_line; + ep_rt_mono_execute_rundown_func ep_rt_mono_execute_rundown; } EventPipeMonoFuncTable; int64_t @@ -430,7 +480,6 @@ ep_rt_mono_fini_providers_and_events (void); void ep_rt_mono_execute_rundown (void); -#ifndef EP_RT_MONO_USE_STATIC_RUNTIME static inline EventPipeMonoFuncTable * @@ -439,7 +488,6 @@ ep_rt_mono_func_table_get (void) extern EventPipeMonoFuncTable _ep_rt_mono_func_table; return &_ep_rt_mono_func_table; } -#endif static inline @@ -612,13 +660,7 @@ inline gboolean ep_rt_mono_rand_try_get_bytes (guchar *buffer, gssize buffer_size, MonoError *error) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME - extern gpointer ep_rt_mono_rand_provider; - g_assert (ep_rt_mono_rand_provider != NULL); - return mono_rand_try_get_bytes (&ep_rt_mono_rand_provider, buffer, buffer_size, error); -#else return ep_rt_mono_func_table_get ()->ep_rt_mono_rand_try_get_bytes (buffer, buffer_size, error); -#endif } static @@ -626,18 +668,7 @@ inline void ep_rt_mono_thread_exited (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME - extern gboolean ep_rt_mono_initialized; - extern MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; - if (ep_rt_mono_initialized) { - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); - if (thread_holder) - thread_holder_free_func (thread_holder); - mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, NULL); - } -#else ep_rt_mono_func_table_get ()->ep_rt_mono_thread_exited (); -#endif } static @@ -681,18 +712,7 @@ inline void ep_rt_mono_thread_setup (bool background_thread) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME - // NOTE, under netcore, only root domain exists. - if (!mono_thread_current ()) { - MonoThread *thread = mono_thread_internal_attach (mono_get_root_domain ()); - if (background_thread && thread) { - mono_thread_set_state (thread, ThreadState_Background); - mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE); - } - } -#else ep_rt_mono_func_table_get ()->ep_rt_mono_thread_attach (background_thread); -#endif } static @@ -700,13 +720,7 @@ inline void ep_rt_mono_thread_teardown (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME - MonoThread *current_thread = mono_thread_current (); - if (current_thread) - mono_thread_internal_detach (current_thread); -#else ep_rt_mono_func_table_get ()->ep_rt_mono_thread_detach (); -#endif } /* @@ -773,11 +787,7 @@ inline void ep_rt_init (void) { -#ifndef EP_RT_MONO_USE_STATIC_RUNTIME mono_eventpipe_init (ep_rt_mono_func_table_get (), thread_holder_alloc_func, thread_holder_free_func); -#else - mono_eventpipe_init (NULL, thread_holder_alloc_func, thread_holder_free_func); -#endif ep_rt_spin_lock_alloc (ep_rt_mono_config_lock_get ()); } @@ -1948,17 +1958,10 @@ inline EventPipeThread * ep_rt_thread_get_or_create (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME - extern MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); - if (!thread_holder) { - thread_holder = thread_holder_alloc_func (); - mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, thread_holder); - } - return ep_thread_holder_get_thread (thread_holder); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_thread_get_or_create (); -#endif + EventPipeThread *thread = ep_rt_thread_get (); + if (!thread) + thread = ep_rt_mono_func_table_get ()->ep_rt_mono_thread_get_or_create (); + return thread; } static diff --git a/src/mono/mono/metadata/icall-eventpipe.c b/src/mono/mono/metadata/icall-eventpipe.c index f3b785fc37c6d1..50ea4b76a4a8dd 100644 --- a/src/mono/mono/metadata/icall-eventpipe.c +++ b/src/mono/mono/metadata/icall-eventpipe.c @@ -12,12 +12,35 @@ #include #include +#include #include #include #include #include #include #include +#include +#include +#include +#include + +// Rundown flags. +#define METHOD_FLAGS_DYNAMIC_METHOD 0x1 +#define METHOD_FLAGS_GENERIC_METHOD 0x2 +#define METHOD_FLAGS_SHARED_GENERIC_METHOD 0x4 +#define METHOD_FLAGS_JITTED_METHOD 0x8 +#define METHOD_FLAGS_JITTED_HELPER_METHOD 0x10 + +#define MODULE_FLAGS_NATIVE_MODULE 0x2 +#define MODULE_FLAGS_DYNAMIC_MODULE 0x4 +#define MODULE_FLAGS_MANIFEST_MODULE 0x8 + +#define ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY 0x2 +#define ASSEMBLY_FLAGS_NATIVE_ASSEMBLY 0x4 +#define ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY 0x8 + +#define DOMAIN_FLAGS_DEFAULT_DOMAIN 0x1 +#define DOMAIN_FLAGS_EXECUTABLE_DOMAIN 0x2 typedef enum _EventPipeActivityControlCode { EP_ACTIVITY_CONTROL_GET_ID = 1, @@ -51,6 +74,13 @@ typedef struct _EventPipeEventInstanceData { uint32_t payload_len; } EventPipeEventInstanceData; +typedef struct _EventPipeFireMethodEventsData{ + MonoDomain *domain; + uint8_t *buffer; + size_t buffer_size; + ep_rt_mono_fire_method_rundown_events_func method_events_func; +} EventPipeFireMethodEventsData; + gboolean ep_rt_mono_initialized; MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; gpointer ep_rt_mono_rand_provider; @@ -58,9 +88,93 @@ gpointer ep_rt_mono_rand_provider; static ep_rt_thread_holder_alloc_func thread_holder_alloc_callback_func; static ep_rt_thread_holder_free_func thread_holder_free_callback_func; +/* + * Forward declares of all static functions. + */ + +static +gboolean +rand_try_get_bytes_func ( + guchar *buffer, + gssize buffer_size, + MonoError *error); + +static +EventPipeThread * +eventpipe_thread_get (void); + +static +EventPipeThread * +eventpipe_thread_get_or_create (void); + +static +void +eventpipe_thread_exited (void); + +static +void +profiler_eventpipe_thread_exited ( + MonoProfiler *prof, + uintptr_t tid); + +static +gpointer +eventpipe_thread_attach (gboolean background_thread); + +static +void +eventpipe_thread_detach (void); + +static +void +eventpipe_fire_method_events ( + MonoJitInfo *ji, + EventPipeFireMethodEventsData *events_data); + +static +void +eventpipe_fire_method_events_func ( + MonoJitInfo *ji, + gpointer user_data); + +static +void +eventpipe_fire_assembly_events ( + MonoDomain *domain, + MonoAssembly *assembly, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func); + +static +gboolean +eventpipe_execute_rundown ( + ep_rt_mono_fire_domain_rundown_events_func domain_events_func, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, + ep_rt_mono_fire_method_rundown_events_func methods_events_func); + + +static +void +delegate_callback_data_free_func ( + EventPipeCallback callback_func, + void *callback_data); + +static +void +delegate_callback_func ( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_context); + static gboolean -rand_try_get_bytes_func (guchar *buffer, gssize buffer_size, MonoError *error) +rand_try_get_bytes_func ( + guchar *buffer, + gssize buffer_size, + MonoError *error) { g_assert (ep_rt_mono_rand_provider != NULL); return mono_rand_try_get_bytes (&ep_rt_mono_rand_provider, buffer, buffer_size, error); @@ -100,7 +214,9 @@ eventpipe_thread_exited (void) static void -profiler_eventpipe_thread_exited (MonoProfiler *prof, uintptr_t tid) +profiler_eventpipe_thread_exited ( + MonoProfiler *prof, + uintptr_t tid) { eventpipe_thread_exited (); } @@ -114,7 +230,7 @@ eventpipe_thread_attach (gboolean background_thread) // NOTE, under netcore, only root domain exists. if (!mono_thread_current ()) { thread = mono_thread_internal_attach (mono_get_root_domain ()); - if (background_thread) { + if (background_thread && thread) { mono_thread_set_state (thread, ThreadState_Background); mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE); } @@ -132,6 +248,249 @@ eventpipe_thread_detach (void) mono_thread_internal_detach (current_thread); } +static +void +eventpipe_fire_method_events ( + MonoJitInfo *ji, + EventPipeFireMethodEventsData *events_data) +{ + g_assert_checked (ji != NULL); + g_assert_checked (events_data->domain != NULL); + g_assert_checked (events_data->method_events_func != NULL); + + uint64_t method_id = 0; + uint64_t module_id = 0; + uint64_t method_code_start = (uint64_t)ji->code_start; + uint32_t method_code_size = (uint32_t)ji->code_size; + uint32_t method_token = 0; + uint32_t method_flags = 0; + uint8_t kind = MONO_CLASS_DEF; + char *method_namespace = NULL; + const char *method_name = NULL; + char *method_signature = NULL; + + //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. + + MonoMethod *method = jinfo_get_method (ji); + if (method) { + method_id = (uint64_t)method; + method_token = method->token; + + if (mono_jit_info_get_generic_sharing_context (ji)) + method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; + + if (method->dynamic) + method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; + + if (!ji->from_aot && !ji->from_llvm) { + method_flags |= METHOD_FLAGS_JITTED_METHOD; + if (method->wrapper_type != MONO_WRAPPER_NONE) + method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; + } + + if (method->is_generic || method->is_inflated) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + + method_name = method->name; + method_signature = mono_signature_full_name (method->signature); + + if (method->klass) { + module_id = (uint64_t)m_class_get_image (method->klass); + kind = m_class_get_class_kind (method->klass); + if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); + } + } + + uint16_t offset_entries = 0; + uint32_t *il_offsets = NULL; + uint32_t *native_offsets = NULL; + + MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, events_data->domain) : NULL; + if (debug_info) { + offset_entries = debug_info->num_line_numbers; + size_t needed_size = (offset_entries * sizeof (uint32_t) * 2); + if (!events_data->buffer || needed_size > events_data->buffer_size) { + g_free (events_data->buffer); + events_data->buffer_size = (size_t)(needed_size * 1.5); + events_data->buffer = g_new (uint8_t, events_data->buffer_size); + } + + if (events_data->buffer) { + il_offsets = (uint32_t*)events_data->buffer; + native_offsets = il_offsets + offset_entries; + + for (int offset_count = 0; offset_count < offset_entries; ++offset_count) { + il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; + native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; + } + } + + mono_debug_free_method_jit_info (debug_info); + } + + if (events_data->buffer && !il_offsets && !native_offsets) { + // No IL offset -> Native offset mapping available. Put all code on IL offset 0. + g_assert_checked (events_data->buffer_size >= sizeof (uint32_t) * 2); + offset_entries = 1; + il_offsets = (uint32_t*)events_data->buffer; + native_offsets = il_offsets + offset_entries; + il_offsets [0] = 0; + native_offsets [0] = (uint32_t)ji->code_size; + } + + events_data->method_events_func ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags, + (ep_char8_t *)method_namespace, + (ep_char8_t *)method_name, + (ep_char8_t *)method_signature, + offset_entries, + il_offsets, + native_offsets, + NULL); + + g_free (method_namespace); + g_free (method_signature); +} + +static +void +eventpipe_fire_method_events_func ( + MonoJitInfo *ji, + gpointer user_data) +{ + EventPipeFireMethodEventsData *events_data = (EventPipeFireMethodEventsData *)user_data; + g_assert_checked (events_data != NULL); + + if (ji && !ji->is_trampoline && !ji->async) + eventpipe_fire_method_events (ji, events_data); +} + +static +void +eventpipe_fire_assembly_events ( + MonoDomain *domain, + MonoAssembly *assembly, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func) +{ + g_assert_checked (domain != NULL); + g_assert_checked (assembly != NULL); + + uint64_t domain_id = (uint64_t)domain; + uint64_t module_id = (uint64_t)assembly->image; + uint64_t assembly_id = (uint64_t)assembly; + + // TODO: Extract all module IL/Native paths and pdb metadata when available. + const char *module_il_path = ""; + const char *module_il_pdb_path = ""; + const char *module_native_path = ""; + const char *module_native_pdb_path = ""; + uint8_t signature [EP_GUID_SIZE] = { 0 }; + uint32_t module_il_pdb_age = 0; + uint32_t module_native_pdb_age = 0; + + uint32_t reserved_flags = 0; + uint64_t binding_id = 0; + + // Native methods are part of JIT table and already emitted. + // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well? + + // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. + uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE; + if (assembly->image) { + if (assembly->image->dynamic) + module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; + if (assembly->image->aot_module) + module_flags |= MODULE_FLAGS_NATIVE_MODULE; + + module_il_path = assembly->image->filename ? assembly->image->filename : ""; + } + + uint32_t assembly_flags = 0; + if (assembly->dynamic) + assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; + + if (assembly->image && assembly->image->aot_module) { + assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; + } + + char *assembly_name = mono_stringify_assembly_name (&assembly->aname); + + assembly_events_func ( + domain_id, + assembly_id, + assembly_flags, + binding_id, + (const ep_char8_t*)assembly_name, + module_id, + module_flags, + reserved_flags, + (const ep_char8_t *)module_il_path, + (const ep_char8_t *)module_native_path, + signature, + module_il_pdb_age, + (const ep_char8_t *)module_il_pdb_path, + signature, + module_native_pdb_age, + (const ep_char8_t *)module_native_pdb_path, + NULL); + + g_free (assembly_name); +} + +static +gboolean +eventpipe_execute_rundown ( + ep_rt_mono_fire_domain_rundown_events_func domain_events_func, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, + ep_rt_mono_fire_method_rundown_events_func method_events_func) +{ + // Under netcore we only have root domain. + MonoDomain *root_domain = mono_get_root_domain (); + if (root_domain) { + uint64_t domain_id = (uint64_t)root_domain; + + // Iterate all functions in use (both JIT and AOT). + EventPipeFireMethodEventsData events_data; + events_data.domain = root_domain; + events_data.buffer_size = 1024 * sizeof(uint32_t); + events_data.buffer = g_new (uint8_t, events_data.buffer_size); + events_data.method_events_func = method_events_func; + jit_info_table_foreach (root_domain, eventpipe_fire_method_events_func, &events_data); + g_free (events_data.buffer); + + // Iterate all assemblies in domain. + GPtrArray *assemblies = mono_domain_get_assemblies (root_domain, FALSE); + if (assemblies) { + for (int i = 0; i < assemblies->len; ++i) { + MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i); + if (assembly) + eventpipe_fire_assembly_events (root_domain, assembly, assembly_events_func); + } + g_ptr_array_free (assemblies, TRUE); + } + + uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN; + const char *domain_name = root_domain->friendly_name ? root_domain->friendly_name : ""; + uint32_t domain_index = 1; + + domain_events_func ( + domain_id, + domain_flags, + (const ep_char8_t *)domain_name, + domain_index, + NULL); + } + + return TRUE; +} + void mono_eventpipe_init ( EventPipeMonoFuncTable *table, @@ -165,6 +524,7 @@ mono_eventpipe_init ( table->ep_rt_mono_thread_detach = eventpipe_thread_detach; table->ep_rt_mono_get_os_cmd_line = mono_get_os_cmd_line; table->ep_rt_mono_get_managed_cmd_line = mono_runtime_get_managed_cmd_line; + table->ep_rt_mono_execute_rundown = eventpipe_execute_rundown; } thread_holder_alloc_callback_func = thread_holder_alloc_func; From a4181927cba53094b9dc8437b4d8f5f3e650bf8f Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 27 Jan 2021 14:14:49 +0100 Subject: [PATCH 5/8] Review feedback. --- src/mono/mono/eglib/eglib-remap.h | 2 ++ src/mono/mono/eglib/giconv.c | 4 ++-- src/mono/mono/eglib/glib.h | 16 ++++++++-------- src/mono/mono/eglib/gmodule-win32.c | 4 ++-- src/mono/mono/eventpipe/ep-rt-mono.c | 6 +++--- src/mono/mono/metadata/domain-internals.h | 2 +- src/mono/mono/metadata/icall-eventpipe.c | 2 +- src/mono/mono/metadata/jit-info.c | 2 +- 8 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/mono/mono/eglib/eglib-remap.h b/src/mono/mono/eglib/eglib-remap.h index 6434803195e847..959d625d0236f1 100644 --- a/src/mono/mono/eglib/eglib-remap.h +++ b/src/mono/mono/eglib/eglib-remap.h @@ -261,6 +261,7 @@ #define g_usleep monoeg_g_usleep #define g_utf16_to_ucs4 monoeg_g_utf16_to_ucs4 #define g_utf16_to_utf8 monoeg_g_utf16_to_utf8 +#define g_utf16_to_utf8_custom_alloc monoeg_g_utf16_to_utf8_custom_alloc #define g_utf16_ascii_equal monoeg_g_utf16_ascii_equal #define g_utf16_asciiz_equal monoeg_g_utf16_asciiz_equal #define g_utf8_jump_table monoeg_g_utf8_jump_table @@ -272,6 +273,7 @@ #define g_utf8_strup monoeg_g_utf8_strup #define g_utf8_to_ucs4_fast monoeg_g_utf8_to_ucs4_fast #define g_utf8_to_utf16 monoeg_g_utf8_to_utf16 +#define g_utf8_to_utf16_custom_alloc monoeg_g_utf8_to_utf16_custom_alloc #define g_utf8_validate monoeg_g_utf8_validate #define g_unichar_to_utf8 monoeg_g_unichar_to_utf8 #define g_unichar_is_space monoeg_g_unichar_is_space diff --git a/src/mono/mono/eglib/giconv.c b/src/mono/mono/eglib/giconv.c index c502e8c71bb4dd..0c5a4fd434a1aa 100644 --- a/src/mono/mono/eglib/giconv.c +++ b/src/mono/mono/eglib/giconv.c @@ -919,7 +919,7 @@ eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong error: if (errno == ENOMEM) { - g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_ALLOC_FAILED, + g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_MEMORY, "Allocation failed."); } else if (errno == EILSEQ) { g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, @@ -1103,7 +1103,7 @@ g_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glo outptr = outbuf = custom_alloc_func (outlen + 1, custom_alloc_data); if (G_UNLIKELY (custom_alloc_func && !outbuf)) { - g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_ALLOC_FAILED, "Allocation failed."); + g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_MEMORY, "Allocation failed."); if (items_written) *items_written = 0; return NULL; diff --git a/src/mono/mono/eglib/glib.h b/src/mono/mono/eglib/glib.h index d58296660d3f55..0b7bc10c32a36a 100644 --- a/src/mono/mono/eglib/glib.h +++ b/src/mono/mono/eglib/glib.h @@ -1005,7 +1005,7 @@ typedef enum { G_CONVERT_ERROR_PARTIAL_INPUT, G_CONVERT_ERROR_BAD_URI, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH, - G_CONVERT_ERROR_ALLOC_FAILED + G_CONVERT_ERROR_NO_MEMORY } GConvertError; gchar *g_utf8_strup (const gchar *str, gssize len); @@ -1038,21 +1038,21 @@ typedef struct { gpointer buffer; gsize buffer_size; gsize req_buffer_size; -} GConvertDefaultCustomAllocatorData; +} GConvertFixedBufferCustomAllocatorData; static gpointer -g_converter_default_custom_allocator_func (gsize req_size, gpointer custom_alloc_data) +g_converter_fixed_buffer_custom_allocator_func (gsize req_size, gpointer custom_alloc_data) { - GConvertDefaultCustomAllocatorData *default_custom_alloc_data = (GConvertDefaultCustomAllocatorData *)custom_alloc_data; - if (!default_custom_alloc_data) + GConvertFixedBufferCustomAllocatorData *fixed_buffer_custom_alloc_data = (GConvertFixedBufferCustomAllocatorData *)custom_alloc_data; + if (!fixed_buffer_custom_alloc_data) return NULL; - default_custom_alloc_data->req_buffer_size = req_size; - if (req_size > default_custom_alloc_data->buffer_size) + fixed_buffer_custom_alloc_data->req_buffer_size = req_size; + if (req_size > fixed_buffer_custom_alloc_data->buffer_size) return NULL; - return default_custom_alloc_data->buffer; + return fixed_buffer_custom_alloc_data->buffer; } gunichar2 *g_utf8_to_utf16_custom_alloc (const gchar *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err); diff --git a/src/mono/mono/eglib/gmodule-win32.c b/src/mono/mono/eglib/gmodule-win32.c index 0a20210f206697..28d050be34e4cd 100644 --- a/src/mono/mono/eglib/gmodule-win32.c +++ b/src/mono/mono/eglib/gmodule-win32.c @@ -172,11 +172,11 @@ g_module_address (void *addr, char *file_name, size_t file_name_len, DWORD bytes = GetModuleFileNameW (module, fname, G_N_ELEMENTS (fname)); if (bytes) { /* Convert back to UTF-8 from wide for runtime */ - GConvertDefaultCustomAllocatorData custom_alloc_data; + GConvertFixedBufferCustomAllocatorData custom_alloc_data; custom_alloc_data.buffer = file_name; custom_alloc_data.buffer_size = file_name_len; custom_alloc_data.req_buffer_size = 0; - if (!g_utf16_to_utf8_custom_alloc (fname, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL)) + if (!g_utf16_to_utf8_custom_alloc (fname, -1, NULL, NULL, g_converter_fixed_buffer_custom_allocator_func, &custom_alloc_data, NULL)) *file_name = '\0'; } else { *file_name = '\0'; diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 9ea4dc462f7392..6edb8edfbf0051 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -607,17 +607,17 @@ write_buffer_string_utf8_t ( if (!value) return true; - GConvertDefaultCustomAllocatorData custom_alloc_data; + GConvertFixedBufferCustomAllocatorData custom_alloc_data; custom_alloc_data.buffer = *buffer + *offset; custom_alloc_data.buffer_size = *size - *offset; custom_alloc_data.req_buffer_size = 0; - if (!g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL)) { + if (!g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_fixed_buffer_custom_allocator_func, &custom_alloc_data, NULL)) { ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + custom_alloc_data.req_buffer_size, fixed_buffer)); custom_alloc_data.buffer = *buffer + *offset; custom_alloc_data.buffer_size = *size - *offset; custom_alloc_data.req_buffer_size = 0; - ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_default_custom_allocator_func, &custom_alloc_data, NULL) != NULL); + ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_fixed_buffer_custom_allocator_func, &custom_alloc_data, NULL) != NULL); } *offset += custom_alloc_data.req_buffer_size; diff --git a/src/mono/mono/metadata/domain-internals.h b/src/mono/mono/metadata/domain-internals.h index 66b316331fbaf7..b33b88e2a463b1 100644 --- a/src/mono/mono/metadata/domain-internals.h +++ b/src/mono/mono/metadata/domain-internals.h @@ -668,7 +668,7 @@ MonoJitInfo* mono_jit_info_table_find_internal (MonoDomain *domain, gpointer add typedef void (*MonoJitInfoFunc) (MonoJitInfo *ji, gpointer user_data); void -jit_info_table_foreach (MonoDomain *domain, MonoJitInfoFunc func, gpointer user_data); +mono_jit_info_table_foreach_internal (MonoDomain *domain, MonoJitInfoFunc func, gpointer user_data); void mono_enable_debug_domain_unload (gboolean enable); diff --git a/src/mono/mono/metadata/icall-eventpipe.c b/src/mono/mono/metadata/icall-eventpipe.c index 50ea4b76a4a8dd..724e4c01c8cd68 100644 --- a/src/mono/mono/metadata/icall-eventpipe.c +++ b/src/mono/mono/metadata/icall-eventpipe.c @@ -462,7 +462,7 @@ eventpipe_execute_rundown ( events_data.buffer_size = 1024 * sizeof(uint32_t); events_data.buffer = g_new (uint8_t, events_data.buffer_size); events_data.method_events_func = method_events_func; - jit_info_table_foreach (root_domain, eventpipe_fire_method_events_func, &events_data); + mono_jit_info_table_foreach_internal (root_domain, eventpipe_fire_method_events_func, &events_data); g_free (events_data.buffer); // Iterate all assemblies in domain. diff --git a/src/mono/mono/metadata/jit-info.c b/src/mono/mono/metadata/jit-info.c index 3fee40d7fac522..d8d318b416c4a1 100644 --- a/src/mono/mono/metadata/jit-info.c +++ b/src/mono/mono/metadata/jit-info.c @@ -338,7 +338,7 @@ mono_jit_info_table_find (MonoDomain *domain, gpointer addr) } void -jit_info_table_foreach (MonoDomain *domain, MonoJitInfoFunc func, gpointer user_data) +mono_jit_info_table_foreach_internal (MonoDomain *domain, MonoJitInfoFunc func, gpointer user_data) { MonoJitInfoTable *table; MonoJitInfo *ji; From 3be418dc8a9072b7bef05f9b26db4f4553948941 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 27 Jan 2021 14:21:03 +0100 Subject: [PATCH 6/8] Remove duplicated test exclusions. --- src/tests/issues.targets | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index e6b06778ce5b3e..99d54290a861f3 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1841,33 +1841,6 @@ needs triage - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - needs triage From 7e31c6e1f3abb5b04f1b54f4c8487fc47904f6bf Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 27 Jan 2021 15:36:11 +0100 Subject: [PATCH 7/8] Fix build warnings + additional name adjustments. --- src/mono/mono/eglib/eglib-remap.h | 1 + src/mono/mono/eglib/giconv.c | 28 +++++++++++++++++++++------- src/mono/mono/eglib/glib.h | 22 +++++----------------- src/mono/mono/eglib/gmodule-win32.c | 4 ++-- src/mono/mono/eventpipe/ep-rt-mono.c | 6 +++--- 5 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/mono/mono/eglib/eglib-remap.h b/src/mono/mono/eglib/eglib-remap.h index 959d625d0236f1..c3e956842dea85 100644 --- a/src/mono/mono/eglib/eglib-remap.h +++ b/src/mono/mono/eglib/eglib-remap.h @@ -29,6 +29,7 @@ #define g_clear_error monoeg_g_clear_error #define g_convert monoeg_g_convert #define g_convert_error_quark monoeg_g_convert_error_quark +#define g_fixed_buffer_custom_allocator monoeg_g_fixed_buffer_custom_allocator #define g_dir_close monoeg_g_dir_close #define g_dir_open monoeg_g_dir_open #define g_dir_read_name monoeg_g_dir_read_name diff --git a/src/mono/mono/eglib/giconv.c b/src/mono/mono/eglib/giconv.c index 0c5a4fd434a1aa..0909ab03d6f794 100644 --- a/src/mono/mono/eglib/giconv.c +++ b/src/mono/mono/eglib/giconv.c @@ -831,7 +831,7 @@ g_utf8_to_ucs4_fast (const gchar *str, glong len, glong *items_written) } static gunichar2 * -eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong *items_written, gboolean include_nuls, gboolean replace_invalid_codepoints, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) +eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong *items_written, gboolean include_nuls, gboolean replace_invalid_codepoints, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { gunichar2 *outbuf, *outptr; size_t outlen = 0; @@ -884,7 +884,7 @@ eg_utf8_to_utf16_general (const gchar *str, glong len, glong *items_read, glong if (G_LIKELY (!custom_alloc_func)) outptr = outbuf = g_malloc ((outlen + 1) * sizeof (gunichar2)); else - outptr = outbuf = custom_alloc_func ((outlen + 1) * sizeof (gunichar2), custom_alloc_data); + outptr = outbuf = (gunichar2 *)custom_alloc_func ((outlen + 1) * sizeof (gunichar2), custom_alloc_data); if (G_UNLIKELY (custom_alloc_func && !outbuf)) { mono_set_errno (ENOMEM); @@ -947,9 +947,9 @@ g_utf8_to_utf16 (const gchar *str, glong len, glong *items_read, glong *items_wr } gunichar2 * -g_utf8_to_utf16_custom_alloc (const gchar *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator cusotm_alloc_func, gpointer custom_alloc_data, GError **err) +g_utf8_to_utf16_custom_alloc (const gchar *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { - return eg_utf8_to_utf16_general (str, len, items_read, items_written, FALSE, FALSE, cusotm_alloc_func, custom_alloc_data, err); + return eg_utf8_to_utf16_general (str, len, items_read, items_written, FALSE, FALSE, custom_alloc_func, custom_alloc_data, err); } gunichar2 * @@ -1038,7 +1038,7 @@ g_utf8_to_ucs4 (const gchar *str, glong len, glong *items_read, glong *items_wri static gchar * -g_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) +g_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { char *inptr, *outbuf, *outptr; size_t outlen = 0; @@ -1100,7 +1100,7 @@ g_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glo if (G_LIKELY (!custom_alloc_func)) outptr = outbuf = g_malloc (outlen + 1); else - outptr = outbuf = custom_alloc_func (outlen + 1, custom_alloc_data); + outptr = outbuf = (char *)custom_alloc_func (outlen + 1, custom_alloc_data); if (G_UNLIKELY (custom_alloc_func && !outbuf)) { g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_MEMORY, "Allocation failed."); @@ -1135,7 +1135,7 @@ g_utf16_to_utf8 (const gunichar2 *str, glong len, glong *items_read, glong *item } gchar * -g_utf16_to_utf8_custom_alloc (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) +g_utf16_to_utf8_custom_alloc (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { return g_utf16_to_utf8_general (str, len, items_read, items_written, custom_alloc_func, custom_alloc_data, err); } @@ -1344,3 +1344,17 @@ g_ucs4_to_utf16 (const gunichar *str, glong len, glong *items_read, glong *items return outbuf; } + +gpointer +g_fixed_buffer_custom_allocator (gsize req_size, gpointer custom_alloc_data) +{ + GFixedBufferCustomAllocatorData *fixed_buffer_custom_alloc_data = (GFixedBufferCustomAllocatorData *)custom_alloc_data; + if (!fixed_buffer_custom_alloc_data) + return NULL; + + fixed_buffer_custom_alloc_data->req_buffer_size = req_size; + if (req_size > fixed_buffer_custom_alloc_data->buffer_size) + return NULL; + + return fixed_buffer_custom_alloc_data->buffer; +} diff --git a/src/mono/mono/eglib/glib.h b/src/mono/mono/eglib/glib.h index 0b7bc10c32a36a..7bdace935e95f9 100644 --- a/src/mono/mono/eglib/glib.h +++ b/src/mono/mono/eglib/glib.h @@ -1032,31 +1032,19 @@ size_t g_utf16_len (const gunichar2 *); #define u16to8(str) g_utf16_to_utf8(str, (glong)strlen(str), NULL, NULL, NULL) #endif -typedef gpointer (*GConvertCustomAllocator) (gsize req_size, gpointer custom_alloc_data); +typedef gpointer (*GCustomAllocator) (gsize req_size, gpointer custom_alloc_data); typedef struct { gpointer buffer; gsize buffer_size; gsize req_buffer_size; -} GConvertFixedBufferCustomAllocatorData; +} GFixedBufferCustomAllocatorData; -static gpointer -g_converter_fixed_buffer_custom_allocator_func (gsize req_size, gpointer custom_alloc_data) -{ - GConvertFixedBufferCustomAllocatorData *fixed_buffer_custom_alloc_data = (GConvertFixedBufferCustomAllocatorData *)custom_alloc_data; - if (!fixed_buffer_custom_alloc_data) - return NULL; - - fixed_buffer_custom_alloc_data->req_buffer_size = req_size; - if (req_size > fixed_buffer_custom_alloc_data->buffer_size) - return NULL; - - return fixed_buffer_custom_alloc_data->buffer; -} +g_fixed_buffer_custom_allocator (gsize req_size, gpointer custom_alloc_data); -gunichar2 *g_utf8_to_utf16_custom_alloc (const gchar *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err); -gchar *g_utf16_to_utf8_custom_alloc (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GConvertCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err); +gunichar2 *g_utf8_to_utf16_custom_alloc (const gchar *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err); +gchar *g_utf16_to_utf8_custom_alloc (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err); /* * Path diff --git a/src/mono/mono/eglib/gmodule-win32.c b/src/mono/mono/eglib/gmodule-win32.c index 28d050be34e4cd..b4521c61cd20fb 100644 --- a/src/mono/mono/eglib/gmodule-win32.c +++ b/src/mono/mono/eglib/gmodule-win32.c @@ -172,11 +172,11 @@ g_module_address (void *addr, char *file_name, size_t file_name_len, DWORD bytes = GetModuleFileNameW (module, fname, G_N_ELEMENTS (fname)); if (bytes) { /* Convert back to UTF-8 from wide for runtime */ - GConvertFixedBufferCustomAllocatorData custom_alloc_data; + GFixedBufferCustomAllocatorData custom_alloc_data; custom_alloc_data.buffer = file_name; custom_alloc_data.buffer_size = file_name_len; custom_alloc_data.req_buffer_size = 0; - if (!g_utf16_to_utf8_custom_alloc (fname, -1, NULL, NULL, g_converter_fixed_buffer_custom_allocator_func, &custom_alloc_data, NULL)) + if (!g_utf16_to_utf8_custom_alloc (fname, -1, NULL, NULL, g_fixed_buffer_custom_allocator, &custom_alloc_data, NULL)) *file_name = '\0'; } else { *file_name = '\0'; diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 6edb8edfbf0051..3cc88969dda0f1 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -607,17 +607,17 @@ write_buffer_string_utf8_t ( if (!value) return true; - GConvertFixedBufferCustomAllocatorData custom_alloc_data; + GFixedBufferCustomAllocatorData custom_alloc_data; custom_alloc_data.buffer = *buffer + *offset; custom_alloc_data.buffer_size = *size - *offset; custom_alloc_data.req_buffer_size = 0; - if (!g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_fixed_buffer_custom_allocator_func, &custom_alloc_data, NULL)) { + if (!g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_fixed_buffer_custom_allocator, &custom_alloc_data, NULL)) { ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + custom_alloc_data.req_buffer_size, fixed_buffer)); custom_alloc_data.buffer = *buffer + *offset; custom_alloc_data.buffer_size = *size - *offset; custom_alloc_data.req_buffer_size = 0; - ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_converter_fixed_buffer_custom_allocator_func, &custom_alloc_data, NULL) != NULL); + ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_fixed_buffer_custom_allocator, &custom_alloc_data, NULL) != NULL); } *offset += custom_alloc_data.req_buffer_size; From d110445a9aa9eb8d39ead1532de99638322d46f1 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 27 Jan 2021 18:02:58 +0100 Subject: [PATCH 8/8] Use eg_ instead of g_ prefix for new static function. --- src/mono/mono/eglib/giconv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/eglib/giconv.c b/src/mono/mono/eglib/giconv.c index 0909ab03d6f794..378b7ef0693848 100644 --- a/src/mono/mono/eglib/giconv.c +++ b/src/mono/mono/eglib/giconv.c @@ -1038,7 +1038,7 @@ g_utf8_to_ucs4 (const gchar *str, glong len, glong *items_read, glong *items_wri static gchar * -g_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) +eg_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { char *inptr, *outbuf, *outptr; size_t outlen = 0; @@ -1131,13 +1131,13 @@ g_utf16_to_utf8_general (const gunichar2 *str, glong len, glong *items_read, glo gchar * g_utf16_to_utf8 (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GError **err) { - return g_utf16_to_utf8_general (str, len, items_read, items_written, NULL, NULL, err); + return eg_utf16_to_utf8_general (str, len, items_read, items_written, NULL, NULL, err); } gchar * g_utf16_to_utf8_custom_alloc (const gunichar2 *str, glong len, glong *items_read, glong *items_written, GCustomAllocator custom_alloc_func, gpointer custom_alloc_data, GError **err) { - return g_utf16_to_utf8_general (str, len, items_read, items_written, custom_alloc_func, custom_alloc_data, err); + return eg_utf16_to_utf8_general (str, len, items_read, items_written, custom_alloc_func, custom_alloc_data, err); } gunichar *