/* * Copyright (c) 2011-2012 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #define __LTTNG_UST_NULL_STRING "(null)" #undef tp_list_for_each_entry_rcu #define tp_list_for_each_entry_rcu(pos, head, member) \ for (pos = cds_list_entry(tp_rcu_dereference_bp((head)->next), __typeof__(*pos), member); \ &pos->member != (head); \ pos = cds_list_entry(tp_rcu_dereference_bp(pos->member.next), __typeof__(*pos), member)) /* * TRACEPOINT_EVENT_CLASS declares a class of tracepoints receiving the * same arguments and having the same field layout. * * TRACEPOINT_EVENT_INSTANCE declares an instance of a tracepoint, with * its own provider and name. It refers to a class (template). * * TRACEPOINT_EVENT declared both a class and an instance and does a * direct mapping from the instance to the class. */ #undef TRACEPOINT_EVENT #define TRACEPOINT_EVENT(_provider, _name, _args, _fields) \ TRACEPOINT_EVENT_CLASS(_provider, _name, \ _TP_PARAMS(_args), \ _TP_PARAMS(_fields)) \ TRACEPOINT_EVENT_INSTANCE(_provider, _name, _name, \ _TP_PARAMS(_args)) /* Helpers */ #define _TP_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define _tp_max_t(type, x, y) \ ({ \ type __max1 = (x); \ type __max2 = (y); \ __max1 > __max2 ? __max1: __max2; \ }) /* * Stage 0 of tracepoint event generation. * * Check that each TRACEPOINT_EVENT provider argument match the * TRACEPOINT_PROVIDER by creating dummy callbacks. */ /* Reset all macros within TRACEPOINT_EVENT */ #include static inline lttng_ust_notrace void _TP_COMBINE_TOKENS(__tracepoint_provider_mismatch_, TRACEPOINT_PROVIDER)(void); static inline void _TP_COMBINE_TOKENS(__tracepoint_provider_mismatch_, TRACEPOINT_PROVIDER)(void) { } #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ __tracepoint_provider_mismatch_##_provider(); #undef TRACEPOINT_EVENT_INSTANCE #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) \ __tracepoint_provider_mismatch_##_provider(); static inline lttng_ust_notrace void _TP_COMBINE_TOKENS(__tracepoint_provider_check_, TRACEPOINT_PROVIDER)(void); static inline void _TP_COMBINE_TOKENS(__tracepoint_provider_check_, TRACEPOINT_PROVIDER)(void) { #include TRACEPOINT_INCLUDE } /* * Stage 0.1 of tracepoint event generation. * * Check that each TRACEPOINT_EVENT provider:name does not exceed the * tracepoint name length limit. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #undef TRACEPOINT_EVENT_INSTANCE #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) \ static const char \ __tp_name_len_check##_provider##___##_name[LTTNG_UST_SYM_NAME_LEN] \ __attribute__((unused)) = \ #_provider ":" #_name; #include TRACEPOINT_INCLUDE /* * Stage 0.2 of tracepoint event generation. * * Create dummy trace prototypes for each event class, and for each used * template. This will allow checking whether the prototypes from the * class and the instance using the class actually match. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ #undef TRACEPOINT_EVENT_INSTANCE #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) \ void __event_template_proto___##_provider##___##_template(_TP_ARGS_DATA_PROTO(_args)); #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ void __event_template_proto___##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); #include TRACEPOINT_INCLUDE /* * Stage 0.9 of tracepoint event generation * * Unfolding the enums */ #include /* Enumeration entry (single value) */ #undef ctf_enum_value #define ctf_enum_value(_string, _value) \ { \ .start = { \ .value = lttng_is_signed_type(__typeof__(_value)) ? \ (long long) (_value) : (_value), \ .signedness = lttng_is_signed_type(__typeof__(_value)), \ }, \ .end = { \ .value = lttng_is_signed_type(__typeof__(_value)) ? \ (long long) (_value) : (_value), \ .signedness = lttng_is_signed_type(__typeof__(_value)), \ }, \ .string = (_string), \ }, /* Enumeration entry (range) */ #undef ctf_enum_range #define ctf_enum_range(_string, _range_start, _range_end) \ { \ .start = { \ .value = lttng_is_signed_type(__typeof__(_range_start)) ? \ (long long) (_range_start) : (_range_start), \ .signedness = lttng_is_signed_type(__typeof__(_range_start)), \ }, \ .end = { \ .value = lttng_is_signed_type(__typeof__(_range_end)) ? \ (long long) (_range_end) : (_range_end), \ .signedness = lttng_is_signed_type(__typeof__(_range_end)), \ }, \ .string = (_string), \ }, /* Enumeration entry (automatic value; follows the rules of CTF) */ #undef ctf_enum_auto #define ctf_enum_auto(_string) \ { \ .start = { \ .value = -1ULL, \ .signedness = 0, \ }, \ .end = { \ .value = -1ULL, \ .signedness = 0, \ }, \ .string = (_string), \ .u = { \ .extra = { \ .options = LTTNG_ENUM_ENTRY_OPTION_IS_AUTO, \ }, \ }, \ }, #undef TP_ENUM_VALUES #define TP_ENUM_VALUES(...) \ __VA_ARGS__ #undef TRACEPOINT_ENUM #define TRACEPOINT_ENUM(_provider, _name, _values) \ const struct lttng_enum_entry __enum_values__##_provider##_##_name[] = { \ _values \ ctf_enum_value("", 0) /* Dummy, 0-len array forbidden by C99. */ \ }; #include TRACEPOINT_INCLUDE /* * Stage 1 of tracepoint event generation. * * Create event field type metadata section. * Each event produce an array of fields. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #include #include #undef _ctf_integer_ext #define _ctf_integer_ext(_type, _item, _src, _byte_order, _base, _nowrite) \ { \ .name = #_item, \ .type = __type_integer(_type, _byte_order, _base, none),\ .nowrite = _nowrite, \ }, #undef _ctf_float #define _ctf_float(_type, _item, _src, _nowrite) \ { \ .name = #_item, \ .type = __type_float(_type), \ .nowrite = _nowrite, \ }, #undef _ctf_array_encoded #define _ctf_array_encoded(_type, _item, _src, _byte_order, \ _length, _encoding, _nowrite, \ _elem_type_base) \ { \ .name = #_item, \ .type = \ { \ .atype = atype_array, \ .u = \ { \ .array = \ { \ .elem_type = __type_integer(_type, _byte_order, _elem_type_base, _encoding), \ .length = _length, \ } \ } \ }, \ .nowrite = _nowrite, \ }, #undef _ctf_sequence_encoded #define _ctf_sequence_encoded(_type, _item, _src, _byte_order, \ _length_type, _src_length, _encoding, _nowrite, \ _elem_type_base) \ { \ .name = #_item, \ .type = \ { \ .atype = atype_sequence, \ .u = \ { \ .sequence = \ { \ .length_type = __type_integer(_length_type, BYTE_ORDER, 10, none), \ .elem_type = __type_integer(_type, _byte_order, _elem_type_base, _encoding), \ }, \ }, \ }, \ .nowrite = _nowrite, \ }, #undef _ctf_string #define _ctf_string(_item, _src, _nowrite) \ { \ .name = #_item, \ .type = \ { \ .atype = atype_string, \ .u = \ { \ .basic = { .string = { .encoding = lttng_encode_UTF8 } } \ }, \ }, \ .nowrite = _nowrite, \ }, #undef _ctf_enum #define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ { \ .name = #_item, \ .type = { \ .atype = atype_enum, \ .u = { \ .basic = { \ .enumeration = { \ .desc = &__enum_##_provider##_##_name, \ .container_type = { \ .size = sizeof(_type) * CHAR_BIT, \ .alignment = lttng_alignof(_type) * CHAR_BIT, \ .signedness = lttng_is_signed_type(_type), \ .reverse_byte_order = 0, \ .base = 10, \ .encoding = lttng_encode_none, \ }, \ }, \ }, \ }, \ }, \ .nowrite = _nowrite, \ }, #undef TP_FIELDS #define TP_FIELDS(...) __VA_ARGS__ /* Only one used in this phase */ #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ static const struct lttng_event_field __event_fields___##_provider##___##_name[] = { \ _fields \ ctf_integer(int, dummy, 0) /* Dummy, C99 forbids 0-len array. */ \ }; #undef TRACEPOINT_ENUM #define TRACEPOINT_ENUM(_provider, _name, _values) \ static const struct lttng_enum_desc __enum_##_provider##_##_name = { \ .name = #_provider "_" #_name, \ .entries = __enum_values__##_provider##_##_name, \ .nr_entries = _TP_ARRAY_SIZE(__enum_values__##_provider##_##_name) - 1, \ }; #include TRACEPOINT_INCLUDE /* * Stage 2 of tracepoint event generation. * * Create probe callback prototypes. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); #include TRACEPOINT_INCLUDE /* * Stage 3.0 of tracepoint event generation. * * Create static inline function that calculates event size. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #include #undef _ctf_integer_ext #define _ctf_integer_ext(_type, _item, _src, _byte_order, _base, _nowrite) \ __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ __event_len += sizeof(_type); #undef _ctf_float #define _ctf_float(_type, _item, _src, _nowrite) \ __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ __event_len += sizeof(_type); #undef _ctf_array_encoded #define _ctf_array_encoded(_type, _item, _src, _byte_order, _length, _encoding, \ _nowrite, _elem_type_base) \ __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ __event_len += sizeof(_type) * (_length); #undef _ctf_sequence_encoded #define _ctf_sequence_encoded(_type, _item, _src, _byte_order, _length_type, \ _src_length, _encoding, _nowrite, _elem_type_base) \ __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_length_type)); \ __event_len += sizeof(_length_type); \ __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ __dynamic_len[__dynamic_len_idx] = (_src_length); \ __event_len += sizeof(_type) * __dynamic_len[__dynamic_len_idx]; \ __dynamic_len_idx++; #undef _ctf_string #define _ctf_string(_item, _src, _nowrite) \ __event_len += __dynamic_len[__dynamic_len_idx++] = \ strlen((_src) ? (_src) : __LTTNG_UST_NULL_STRING) + 1; #undef _ctf_enum #define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ #undef TP_FIELDS #define TP_FIELDS(...) __VA_ARGS__ #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ static inline lttng_ust_notrace \ size_t __event_get_size__##_provider##___##_name(size_t *__dynamic_len, _TP_ARGS_DATA_PROTO(_args)); \ static inline \ size_t __event_get_size__##_provider##___##_name(size_t *__dynamic_len, _TP_ARGS_DATA_PROTO(_args)) \ { \ size_t __event_len = 0; \ unsigned int __dynamic_len_idx = 0; \ \ if (0) \ (void) __dynamic_len_idx; /* don't warn if unused */ \ _fields \ return __event_len; \ } #include TRACEPOINT_INCLUDE /* * Stage 3.1 of tracepoint event generation. * * Create static inline function that layout the filter stack data. * We make both write and nowrite data available to the filter. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #include #include #undef _ctf_integer_ext #define _ctf_integer_ext(_type, _item, _src, _byte_order, _base, _nowrite) \ if (lttng_is_signed_type(_type)) { \ int64_t __ctf_tmp_int64; \ switch (sizeof(_type)) { \ case 1: \ { \ union { _type t; int8_t v; } __tmp = { (_type) (_src) }; \ __ctf_tmp_int64 = (int64_t) __tmp.v; \ break; \ } \ case 2: \ { \ union { _type t; int16_t v; } __tmp = { (_type) (_src) }; \ if (_byte_order != BYTE_ORDER) \ __tmp.v = bswap_16(__tmp.v); \ __ctf_tmp_int64 = (int64_t) __tmp.v; \ break; \ } \ case 4: \ { \ union { _type t; int32_t v; } __tmp = { (_type) (_src) }; \ if (_byte_order != BYTE_ORDER) \ __tmp.v = bswap_32(__tmp.v); \ __ctf_tmp_int64 = (int64_t) __tmp.v; \ break; \ } \ case 8: \ { \ union { _type t; int64_t v; } __tmp = { (_type) (_src) }; \ if (_byte_order != BYTE_ORDER) \ __tmp.v = bswap_64(__tmp.v); \ __ctf_tmp_int64 = (int64_t) __tmp.v; \ break; \ } \ default: \ abort(); \ }; \ memcpy(__stack_data, &__ctf_tmp_int64, sizeof(int64_t)); \ } else { \ uint64_t __ctf_tmp_uint64; \ switch (sizeof(_type)) { \ case 1: \ { \ union { _type t; uint8_t v; } __tmp = { (_type) (_src) }; \ __ctf_tmp_uint64 = (uint64_t) __tmp.v; \ break; \ } \ case 2: \ { \ union { _type t; uint16_t v; } __tmp = { (_type) (_src) }; \ if (_byte_order != BYTE_ORDER) \ __tmp.v = bswap_16(__tmp.v); \ __ctf_tmp_uint64 = (uint64_t) __tmp.v; \ break; \ } \ case 4: \ { \ union { _type t; uint32_t v; } __tmp = { (_type) (_src) }; \ if (_byte_order != BYTE_ORDER) \ __tmp.v = bswap_32(__tmp.v); \ __ctf_tmp_uint64 = (uint64_t) __tmp.v; \ break; \ } \ case 8: \ { \ union { _type t; uint64_t v; } __tmp = { (_type) (_src) }; \ if (_byte_order != BYTE_ORDER) \ __tmp.v = bswap_64(__tmp.v); \ __ctf_tmp_uint64 = (uint64_t) __tmp.v; \ break; \ } \ default: \ abort(); \ }; \ memcpy(__stack_data, &__ctf_tmp_uint64, sizeof(uint64_t)); \ } \ __stack_data += sizeof(int64_t); #undef _ctf_float #define _ctf_float(_type, _item, _src, _nowrite) \ { \ double __ctf_tmp_double = (double) (_type) (_src); \ memcpy(__stack_data, &__ctf_tmp_double, sizeof(double)); \ __stack_data += sizeof(double); \ } #undef _ctf_array_encoded #define _ctf_array_encoded(_type, _item, _src, _byte_order, _length, \ _encoding, _nowrite, _elem_type_base) \ { \ unsigned long __ctf_tmp_ulong = (unsigned long) (_length); \ const void *__ctf_tmp_ptr = (_src); \ memcpy(__stack_data, &__ctf_tmp_ulong, sizeof(unsigned long)); \ __stack_data += sizeof(unsigned long); \ memcpy(__stack_data, &__ctf_tmp_ptr, sizeof(void *)); \ __stack_data += sizeof(void *); \ } #undef _ctf_sequence_encoded #define _ctf_sequence_encoded(_type, _item, _src, _byte_order, _length_type, \ _src_length, _encoding, _nowrite, _elem_type_base) \ { \ unsigned long __ctf_tmp_ulong = (unsigned long) (_src_length); \ const void *__ctf_tmp_ptr = (_src); \ memcpy(__stack_data, &__ctf_tmp_ulong, sizeof(unsigned long)); \ __stack_data += sizeof(unsigned long); \ memcpy(__stack_data, &__ctf_tmp_ptr, sizeof(void *)); \ __stack_data += sizeof(void *); \ } #undef _ctf_string #define _ctf_string(_item, _src, _nowrite) \ { \ const void *__ctf_tmp_ptr = \ ((_src) ? (_src) : __LTTNG_UST_NULL_STRING); \ memcpy(__stack_data, &__ctf_tmp_ptr, sizeof(void *)); \ __stack_data += sizeof(void *); \ } #undef _ctf_enum #define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ #undef TP_FIELDS #define TP_FIELDS(...) __VA_ARGS__ #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ static inline \ void __event_prepare_filter_stack__##_provider##___##_name(char *__stack_data,\ _TP_ARGS_DATA_PROTO(_args)) \ { \ _fields \ } #include TRACEPOINT_INCLUDE /* * Stage 4 of tracepoint event generation. * * Create static inline function that calculates event payload alignment. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #include #undef _ctf_integer_ext #define _ctf_integer_ext(_type, _item, _src, _byte_order, _base, _nowrite) \ __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); #undef _ctf_float #define _ctf_float(_type, _item, _src, _nowrite) \ __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); #undef _ctf_array_encoded #define _ctf_array_encoded(_type, _item, _src, _byte_order, _length, \ _encoding, _nowrite, _elem_type_base) \ __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); #undef _ctf_sequence_encoded #define _ctf_sequence_encoded(_type, _item, _src, _byte_order, _length_type, \ _src_length, _encoding, _nowrite, _elem_type_base) \ __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_length_type)); \ __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); #undef _ctf_string #define _ctf_string(_item, _src, _nowrite) #undef _ctf_enum #define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ #undef TP_FIELDS #define TP_FIELDS(...) __VA_ARGS__ #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ static inline lttng_ust_notrace \ size_t __event_get_align__##_provider##___##_name(_TP_ARGS_PROTO(_args)); \ static inline \ size_t __event_get_align__##_provider##___##_name(_TP_ARGS_PROTO(_args)) \ { \ size_t __event_align = 1; \ _fields \ return __event_align; \ } #include TRACEPOINT_INCLUDE /* * Stage 5 of tracepoint event generation. * * Create the probe function. This function calls event size calculation * and writes event data into the buffer. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #include #undef _ctf_integer_ext #define _ctf_integer_ext(_type, _item, _src, _byte_order, _base, _nowrite) \ { \ _type __tmp = (_src); \ lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__tmp));\ __chan->ops->event_write(&__ctx, &__tmp, sizeof(__tmp));\ } #undef _ctf_float #define _ctf_float(_type, _item, _src, _nowrite) \ { \ _type __tmp = (_src); \ lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__tmp));\ __chan->ops->event_write(&__ctx, &__tmp, sizeof(__tmp));\ } #undef _ctf_array_encoded #define _ctf_array_encoded(_type, _item, _src, _byte_order, _length, \ _encoding, _nowrite, _elem_type_base) \ lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(_type)); \ __chan->ops->event_write(&__ctx, _src, sizeof(_type) * (_length)); #undef _ctf_sequence_encoded #define _ctf_sequence_encoded(_type, _item, _src, _byte_order, _length_type, \ _src_length, _encoding, _nowrite, _elem_type_base) \ { \ _length_type __tmpl = __stackvar.__dynamic_len[__dynamic_len_idx]; \ lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(_length_type));\ __chan->ops->event_write(&__ctx, &__tmpl, sizeof(_length_type));\ } \ lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(_type)); \ __chan->ops->event_write(&__ctx, _src, \ sizeof(_type) * __get_dynamic_len(dest)); /* * __chan->ops->u.has_strcpy is a flag letting us know if the LTTng-UST * tracepoint provider ABI implements event_strcpy. This dynamic check * can be removed when the tracepoint provider ABI moves to 2. */ #if (LTTNG_UST_PROVIDER_MAJOR > 1) #error "Tracepoint probe provider major version has changed. Please remove dynamic check for has_strcpy." #endif #undef _ctf_string #define _ctf_string(_item, _src, _nowrite) \ { \ const char *__ctf_tmp_string = \ ((_src) ? (_src) : __LTTNG_UST_NULL_STRING); \ lib_ring_buffer_align_ctx(&__ctx, \ lttng_alignof(*__ctf_tmp_string)); \ if (__chan->ops->u.has_strcpy) \ __chan->ops->event_strcpy(&__ctx, __ctf_tmp_string, \ __get_dynamic_len(dest)); \ else \ __chan->ops->event_write(&__ctx, __ctf_tmp_string, \ __get_dynamic_len(dest)); \ } #undef _ctf_enum #define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \ _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite) /* Beware: this get len actually consumes the len value */ #undef __get_dynamic_len #define __get_dynamic_len(field) __stackvar.__dynamic_len[__dynamic_len_idx++] #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ #undef TP_FIELDS #define TP_FIELDS(...) __VA_ARGS__ /* * For state dump, check that "session" argument (mandatory) matches the * session this event belongs to. Ensures that we write state dump data only * into the started session, not into all sessions. */ #undef _TP_SESSION_CHECK #ifdef TP_SESSION_CHECK #define _TP_SESSION_CHECK(session, csession) (session == csession) #else /* TP_SESSION_CHECK */ #define _TP_SESSION_CHECK(session, csession) 1 #endif /* TP_SESSION_CHECK */ /* * Use of __builtin_return_address(0) sometimes seems to cause stack * corruption on 32-bit PowerPC. Disable this feature on that * architecture for now by always using the NULL value for the ip * context. */ #undef _TP_IP_PARAM #ifdef TP_IP_PARAM #define _TP_IP_PARAM(x) (x) #else /* TP_IP_PARAM */ #if defined(__PPC__) && !defined(__PPC64__) #define _TP_IP_PARAM(x) NULL #else /* #if defined(__PPC__) && !defined(__PPC64__) */ #define _TP_IP_PARAM(x) __builtin_return_address(0) #endif /* #else #if defined(__PPC__) && !defined(__PPC64__) */ #endif /* TP_IP_PARAM */ /* * Using twice size for filter stack data to hold size and pointer for * each field (worse case). For integers, max size required is 64-bit. * Same for double-precision floats. Those fit within * 2*sizeof(unsigned long) for all supported architectures. * Perform UNION (||) of filter runtime list. */ #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ static lttng_ust_notrace \ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); \ static \ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \ { \ struct lttng_event *__event = (struct lttng_event *) __tp_data; \ struct lttng_channel *__chan = __event->chan; \ struct lttng_ust_lib_ring_buffer_ctx __ctx; \ struct lttng_stack_ctx __lttng_ctx; \ size_t __event_len, __event_align; \ size_t __dynamic_len_idx = 0; \ union { \ size_t __dynamic_len[_TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1]; \ char __filter_stack_data[2 * sizeof(unsigned long) * (_TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1)]; \ } __stackvar; \ int __ret; \ \ if (0) \ (void) __dynamic_len_idx; /* don't warn if unused */ \ if (!_TP_SESSION_CHECK(session, __chan->session)) \ return; \ if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->session->active))) \ return; \ if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->enabled))) \ return; \ if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled))) \ return; \ if (caa_unlikely(!TP_RCU_LINK_TEST())) \ return; \ if (caa_unlikely(!cds_list_empty(&__event->bytecode_runtime_head))) { \ struct lttng_bytecode_runtime *bc_runtime; \ int __filter_record = __event->has_enablers_without_bytecode; \ \ __event_prepare_filter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \ _TP_ARGS_DATA_VAR(_args)); \ tp_list_for_each_entry_rcu(bc_runtime, &__event->bytecode_runtime_head, node) { \ if (caa_unlikely(bc_runtime->filter(bc_runtime, \ __stackvar.__filter_stack_data) & LTTNG_FILTER_RECORD_FLAG)) \ __filter_record = 1; \ } \ if (caa_likely(!__filter_record)) \ return; \ } \ __event_len = __event_get_size__##_provider##___##_name(__stackvar.__dynamic_len, \ _TP_ARGS_DATA_VAR(_args)); \ __event_align = __event_get_align__##_provider##___##_name(_TP_ARGS_VAR(_args)); \ memset(&__lttng_ctx, 0, sizeof(__lttng_ctx)); \ __lttng_ctx.event = __event; \ __lttng_ctx.chan_ctx = tp_rcu_dereference_bp(__chan->ctx); \ __lttng_ctx.event_ctx = tp_rcu_dereference_bp(__event->ctx); \ lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \ __event_align, -1, __chan->handle, &__lttng_ctx); \ __ctx.ip = _TP_IP_PARAM(TP_IP_PARAM); \ __ret = __chan->ops->event_reserve(&__ctx, __event->id); \ if (__ret < 0) \ return; \ _fields \ __chan->ops->event_commit(&__ctx); \ } #include TRACEPOINT_INCLUDE #undef __get_dynamic_len /* * Stage 5.1 of tracepoint event generation. * * Create probe signature */ /* Reset all macros within TRACEPOINT_EVENT */ #include #undef TP_ARGS #define TP_ARGS(...) __VA_ARGS__ #define _TP_EXTRACT_STRING2(...) #__VA_ARGS__ #undef TRACEPOINT_EVENT_CLASS #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ static const char __tp_event_signature___##_provider##___##_name[] = \ _TP_EXTRACT_STRING2(_args); #include TRACEPOINT_INCLUDE #undef _TP_EXTRACT_STRING2 /* * Stage 6 of tracepoint event generation. * * Tracepoint loglevel mapping definition generation. We generate a * symbol for each mapping for a provider/event to ensure at most a 1 to * 1 mapping between events and loglevels. If the symbol is repeated, * the compiler will complain. */ /* Reset all macros within TRACEPOINT_EVENT */ #include /* * Declare _loglevel___##__provider##___##__name as non-static, with * hidden visibility for c++ handling of weakref. We do a weakref to the * symbol in a later stage, which requires that the symbol is not * mangled. */ #ifdef __cplusplus #define LTTNG_TP_EXTERN_C extern "C" #else #define LTTNG_TP_EXTERN_C #endif #undef TRACEPOINT_LOGLEVEL #define TRACEPOINT_LOGLEVEL(__provider, __name, __loglevel) \ static const int _loglevel_value___##__provider##___##__name = __loglevel; \ LTTNG_TP_EXTERN_C const int *_loglevel___##__provider##___##__name \ __attribute__((visibility("hidden"))) = \ &_loglevel_value___##__provider##___##__name; #include TRACEPOINT_INCLUDE #undef LTTNG_TP_EXTERN_C /* * Stage 6.1 of tracepoint event generation. * * Tracepoint UML URI info. */ /* Reset all macros within TRACEPOINT_EVENT */ #include /* * Declare _model_emf_uri___##__provider##___##__name as non-static, * with hidden visibility for c++ handling of weakref. We do a weakref * to the symbol in a later stage, which requires that the symbol is not * mangled. */ #ifdef __cplusplus #define LTTNG_TP_EXTERN_C extern "C" #else #define LTTNG_TP_EXTERN_C #endif #undef TRACEPOINT_MODEL_EMF_URI #define TRACEPOINT_MODEL_EMF_URI(__provider, __name, __uri) \ LTTNG_TP_EXTERN_C const char *_model_emf_uri___##__provider##___##__name \ __attribute__((visibility("hidden"))) = __uri; \ #include TRACEPOINT_INCLUDE #undef LTTNG_TP_EXTERN_C /* * Stage 7.1 of tracepoint event generation. * * Create events description structures. We use a weakref because * loglevels are optional. If not declared, the event will point to the * a loglevel that contains NULL. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #undef TRACEPOINT_EVENT_INSTANCE #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) \ static const int * \ __ref_loglevel___##_provider##___##_name \ __attribute__((weakref ("_loglevel___" #_provider "___" #_name))); \ static const char * \ __ref_model_emf_uri___##_provider##___##_name \ __attribute__((weakref ("_model_emf_uri___" #_provider "___" #_name)));\ static const struct lttng_event_desc __event_desc___##_provider##_##_name = { \ .name = #_provider ":" #_name, \ .probe_callback = (void (*)(void)) &__event_probe__##_provider##___##_template,\ .ctx = NULL, \ .fields = __event_fields___##_provider##___##_template, \ .nr_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_template) - 1, \ .loglevel = &__ref_loglevel___##_provider##___##_name, \ .signature = __tp_event_signature___##_provider##___##_template, \ .u = { \ .ext = { \ .model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name, \ }, \ }, \ }; #include TRACEPOINT_INCLUDE /* * Stage 7.2 of tracepoint event generation. * * Create array of events. */ /* Reset all macros within TRACEPOINT_EVENT */ #include #undef TRACEPOINT_EVENT_INSTANCE #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) \ &__event_desc___##_provider##_##_name, static const struct lttng_event_desc *_TP_COMBINE_TOKENS(__event_desc___, TRACEPOINT_PROVIDER)[] = { #include TRACEPOINT_INCLUDE NULL, /* Dummy, C99 forbids 0-len array. */ }; /* * Stage 8 of tracepoint event generation. * * Create a toplevel descriptor for the whole probe. */ /* non-const because list head will be modified when registered. */ static struct lttng_probe_desc _TP_COMBINE_TOKENS(__probe_desc___, TRACEPOINT_PROVIDER) = { .provider = __tp_stringify(TRACEPOINT_PROVIDER), .event_desc = _TP_COMBINE_TOKENS(__event_desc___, TRACEPOINT_PROVIDER), .nr_events = _TP_ARRAY_SIZE(_TP_COMBINE_TOKENS(__event_desc___, TRACEPOINT_PROVIDER)) - 1, .head = { NULL, NULL }, .lazy_init_head = { NULL, NULL }, .lazy = 0, .major = LTTNG_UST_PROVIDER_MAJOR, .minor = LTTNG_UST_PROVIDER_MINOR, }; static int _TP_COMBINE_TOKENS(__probe_register_refcount___, TRACEPOINT_PROVIDER); /* * Stage 9 of tracepoint event generation. * * Register/unregister probes at module load/unload. * * Generate the constructor as an externally visible symbol for use when * linking the probe statically. * * Register refcount is protected by libc dynamic loader mutex. */ /* Reset all macros within TRACEPOINT_EVENT */ #include static void lttng_ust_notrace __attribute__((constructor)) _TP_COMBINE_TOKENS(__lttng_events_init__, TRACEPOINT_PROVIDER)(void); static void _TP_COMBINE_TOKENS(__lttng_events_init__, TRACEPOINT_PROVIDER)(void) { int ret; if (_TP_COMBINE_TOKENS(__probe_register_refcount___, TRACEPOINT_PROVIDER)++) { return; } /* * __tracepoint_provider_check_ ## TRACEPOINT_PROVIDER() is a * static inline function that ensures every probe PROVIDER * argument match the provider within which they appear. It * calls empty static inline functions, and therefore has no * runtime effect. However, if it detects an error, a linker * error will appear. */ _TP_COMBINE_TOKENS(__tracepoint_provider_check_, TRACEPOINT_PROVIDER)(); ret = lttng_probe_register(&_TP_COMBINE_TOKENS(__probe_desc___, TRACEPOINT_PROVIDER)); if (ret) { fprintf(stderr, "LTTng-UST: Error (%d) while registering tracepoint probe.\n", ret); abort(); } } static void lttng_ust_notrace __attribute__((destructor)) _TP_COMBINE_TOKENS(__lttng_events_exit__, TRACEPOINT_PROVIDER)(void); static void _TP_COMBINE_TOKENS(__lttng_events_exit__, TRACEPOINT_PROVIDER)(void) { if (--_TP_COMBINE_TOKENS(__probe_register_refcount___, TRACEPOINT_PROVIDER)) { return; } lttng_probe_unregister(&_TP_COMBINE_TOKENS(__probe_desc___, TRACEPOINT_PROVIDER)); } int _TP_COMBINE_TOKENS(__tracepoint_provider_, TRACEPOINT_PROVIDER);