X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=include%2Flttng%2Ftracepoint.h;h=d77a2fb298c40f99c7fd290eb48eda48d36bcae9;hb=0fd0de100bc6633e8ecf575301dc92321db32575;hp=fb635c111327e86a20a6898d364f3e175acb9a85;hpb=46c881a7d6839761e3371a93ba29e7a0202bcd03;p=lttng-ust.git diff --git a/include/lttng/tracepoint.h b/include/lttng/tracepoint.h index fb635c11..d77a2fb2 100644 --- a/include/lttng/tracepoint.h +++ b/include/lttng/tracepoint.h @@ -23,31 +23,40 @@ * SOFTWARE. */ +#include +#include #include #include #include +#include #include /* for dlopen */ #include /* for memset */ -#include #include /* for sdt */ #include #ifdef LTTNG_UST_HAVE_SDT_INTEGRATION #define SDT_USE_VARIADIC #include +#define LTTNG_STAP_PROBEV STAP_PROBEV #else -#define STAP_PROBEV(...) +#define LTTNG_STAP_PROBEV(...) #endif #ifdef __cplusplus extern "C" { #endif +#define tracepoint_enabled(provider, name) \ + caa_unlikely(CMM_LOAD_SHARED(__tracepoint_##provider##___##name.state)) + +#define do_tracepoint(provider, name, ...) \ + __tracepoint_cb_##provider##___##name(__VA_ARGS__) + #define tracepoint(provider, name, ...) \ do { \ - STAP_PROBEV(provider, name, ## __VA_ARGS__); \ - if (caa_unlikely(__tracepoint_##provider##___##name.state)) \ - __tracepoint_cb_##provider##___##name(__VA_ARGS__); \ + LTTNG_STAP_PROBEV(provider, name, ## __VA_ARGS__); \ + if (tracepoint_enabled(provider, name)) \ + do_tracepoint(provider, name, __VA_ARGS__); \ } while (0) #define TP_ARGS(...) __VA_ARGS__ @@ -144,14 +153,19 @@ extern "C" { #define _TP_ARGS_DATA_VAR(...) _TP_DATA_VAR_N(_TP_NARGS(0, ##__VA_ARGS__), ##__VA_ARGS__) #define _TP_PARAMS(...) __VA_ARGS__ +/* + * The tracepoint cb is marked always inline so we can distinguish + * between caller's ip addresses within the probe using the return + * address. + */ #define _DECLARE_TRACEPOINT(_provider, _name, ...) \ -extern struct tracepoint __tracepoint_##_provider##___##_name; \ -static inline lttng_ust_notrace \ +extern struct lttng_ust_tracepoint __tracepoint_##_provider##___##_name; \ +static inline __attribute__((always_inline, unused)) lttng_ust_notrace \ void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)); \ -static inline \ +static \ void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)) \ { \ - struct tracepoint_probe *__tp_probe; \ + struct lttng_ust_tracepoint_probe *__tp_probe; \ \ if (caa_unlikely(!TP_RCU_LINK_TEST())) \ return; \ @@ -160,7 +174,7 @@ void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)) \ if (caa_unlikely(!__tp_probe)) \ goto end; \ do { \ - void (*__tp_cb)(void) = __tp_probe->func; \ + void (*__tp_cb)(void) = __tp_probe->func; \ void *__tp_data = __tp_probe->data; \ \ URCU_FORCE_CAST(void (*)(_TP_ARGS_DATA_PROTO(__VA_ARGS__)), __tp_cb) \ @@ -198,22 +212,19 @@ extern int __tracepoint_probe_unregister(const char *name, void (*func)(void), * tracepoint dynamic linkage handling (callbacks). Hidden visibility: * shared across objects in a module/main executable. */ -struct tracepoint_dlopen { +struct lttng_ust_tracepoint_dlopen { void *liblttngust_handle; - int (*tracepoint_register_lib)(struct tracepoint * const *tracepoints_start, + int (*tracepoint_register_lib)(struct lttng_ust_tracepoint * const *tracepoints_start, int tracepoints_count); - int (*tracepoint_unregister_lib)(struct tracepoint * const *tracepoints_start); -#ifndef _LGPL_SOURCE + int (*tracepoint_unregister_lib)(struct lttng_ust_tracepoint * const *tracepoints_start); void (*rcu_read_lock_sym_bp)(void); void (*rcu_read_unlock_sym_bp)(void); void *(*rcu_dereference_sym_bp)(void *p); -#endif }; -extern struct tracepoint_dlopen tracepoint_dlopen; - -#if defined(TRACEPOINT_DEFINE) || defined(TRACEPOINT_CREATE_PROBES) +extern struct lttng_ust_tracepoint_dlopen tracepoint_dlopen; +extern struct lttng_ust_tracepoint_dlopen *tracepoint_dlopen_ptr; /* * These weak symbols, the constructor, and destructor take care of @@ -224,44 +235,109 @@ int __tracepoint_registered __attribute__((weak, visibility("hidden"))); int __tracepoint_ptrs_registered __attribute__((weak, visibility("hidden"))); -struct tracepoint_dlopen tracepoint_dlopen +struct lttng_ust_tracepoint_dlopen tracepoint_dlopen + __attribute__((weak, visibility("hidden"))); +/* + * Deal with gcc O1 optimisation issues with weak hidden symbols. gcc + * 4.8 and prior does not have the same behavior for symbol scoping on + * 32-bit powerpc depending on the object size: symbols for objects of 8 + * bytes or less have the same address throughout a module, whereas they + * have different addresses between compile units for objects larger + * than 8 bytes. Add this pointer indirection to ensure that the symbol + * scoping match that of the other weak hidden symbols found in this + * header. + */ +struct lttng_ust_tracepoint_dlopen *tracepoint_dlopen_ptr __attribute__((weak, visibility("hidden"))); +/* + * Tracepoint dynamic linkage handling (callbacks). Hidden visibility: shared + * across objects in a module/main executable. The callbacks are used to + * control and check if the destructors should be executed. + */ +struct lttng_ust_tracepoint_destructors_syms { + int *old_tracepoint_disable_destructors; + void (*tracepoint_disable_destructors)(void); + int (*tracepoint_get_destructors_state)(void); +}; + +extern struct lttng_ust_tracepoint_destructors_syms tracepoint_destructors_syms; +extern struct lttng_ust_tracepoint_destructors_syms *tracepoint_destructors_syms_ptr; + +struct lttng_ust_tracepoint_destructors_syms tracepoint_destructors_syms + __attribute__((weak, visibility("hidden"))); +struct lttng_ust_tracepoint_destructors_syms *tracepoint_destructors_syms_ptr + __attribute__((weak, visibility("hidden"))); + +static inline void tracepoint_disable_destructors(void) +{ + if (!tracepoint_dlopen_ptr) + tracepoint_dlopen_ptr = &tracepoint_dlopen; + if (!tracepoint_destructors_syms_ptr) + tracepoint_destructors_syms_ptr = &tracepoint_destructors_syms; + if (tracepoint_dlopen_ptr->liblttngust_handle + && tracepoint_destructors_syms_ptr->tracepoint_disable_destructors) + tracepoint_destructors_syms_ptr->tracepoint_disable_destructors(); + *tracepoint_destructors_syms_ptr->old_tracepoint_disable_destructors = 1; +} + +#ifndef _LGPL_SOURCE +static inline void lttng_ust_notrace +__tracepoint__init_urcu_sym(void); +static inline void +__tracepoint__init_urcu_sym(void) +{ + if (!tracepoint_dlopen_ptr) + tracepoint_dlopen_ptr = &tracepoint_dlopen; + /* + * Symbols below are needed by tracepoint call sites and probe + * providers. + */ + if (!tracepoint_dlopen_ptr->rcu_read_lock_sym_bp) + tracepoint_dlopen_ptr->rcu_read_lock_sym_bp = + URCU_FORCE_CAST(void (*)(void), + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "tp_rcu_read_lock_bp")); + if (!tracepoint_dlopen_ptr->rcu_read_unlock_sym_bp) + tracepoint_dlopen_ptr->rcu_read_unlock_sym_bp = + URCU_FORCE_CAST(void (*)(void), + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "tp_rcu_read_unlock_bp")); + if (!tracepoint_dlopen_ptr->rcu_dereference_sym_bp) + tracepoint_dlopen_ptr->rcu_dereference_sym_bp = + URCU_FORCE_CAST(void *(*)(void *p), + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "tp_rcu_dereference_sym_bp")); +} +#else +static inline void lttng_ust_notrace +__tracepoint__init_urcu_sym(void); +static inline void +__tracepoint__init_urcu_sym(void) +{ +} +#endif + static void lttng_ust_notrace __attribute__((constructor)) __tracepoints__init(void); static void __tracepoints__init(void) { - if (__tracepoint_registered++) + if (__tracepoint_registered++) { + if (!tracepoint_dlopen_ptr->liblttngust_handle) + return; + __tracepoint__init_urcu_sym(); return; + } - if (!tracepoint_dlopen.liblttngust_handle) - tracepoint_dlopen.liblttngust_handle = + if (!tracepoint_dlopen_ptr) + tracepoint_dlopen_ptr = &tracepoint_dlopen; + if (!tracepoint_dlopen_ptr->liblttngust_handle) + tracepoint_dlopen_ptr->liblttngust_handle = dlopen("liblttng-ust-tracepoint.so.0", RTLD_NOW | RTLD_GLOBAL); - if (!tracepoint_dlopen.liblttngust_handle) + if (!tracepoint_dlopen_ptr->liblttngust_handle) return; - tracepoint_dlopen.tracepoint_register_lib = - URCU_FORCE_CAST(int (*)(struct tracepoint * const *, int), - dlsym(tracepoint_dlopen.liblttngust_handle, - "tracepoint_register_lib")); - tracepoint_dlopen.tracepoint_unregister_lib = - URCU_FORCE_CAST(int (*)(struct tracepoint * const *), - dlsym(tracepoint_dlopen.liblttngust_handle, - "tracepoint_unregister_lib")); -#ifndef _LGPL_SOURCE - tracepoint_dlopen.rcu_read_lock_sym_bp = - URCU_FORCE_CAST(void (*)(void), - dlsym(tracepoint_dlopen.liblttngust_handle, - "tp_rcu_read_lock_bp")); - tracepoint_dlopen.rcu_read_unlock_sym_bp = - URCU_FORCE_CAST(void (*)(void), - dlsym(tracepoint_dlopen.liblttngust_handle, - "tp_rcu_read_unlock_bp")); - tracepoint_dlopen.rcu_dereference_sym_bp = - URCU_FORCE_CAST(void *(*)(void *p), - dlsym(tracepoint_dlopen.liblttngust_handle, - "tp_rcu_dereference_sym_bp")); -#endif + __tracepoint__init_urcu_sym(); } static void lttng_ust_notrace __attribute__((destructor)) @@ -273,14 +349,46 @@ __tracepoints__destroy(void) if (--__tracepoint_registered) return; - if (tracepoint_dlopen.liblttngust_handle && !__tracepoint_ptrs_registered) { - ret = dlclose(tracepoint_dlopen.liblttngust_handle); - assert(!ret); - memset(&tracepoint_dlopen, 0, sizeof(tracepoint_dlopen)); + if (!tracepoint_dlopen_ptr) + tracepoint_dlopen_ptr = &tracepoint_dlopen; + if (!tracepoint_destructors_syms_ptr) + tracepoint_destructors_syms_ptr = &tracepoint_destructors_syms; + if (!tracepoint_dlopen_ptr->liblttngust_handle) + return; + if (__tracepoint_ptrs_registered) + return; + /* + * Lookup if destructors must be executed using the new method. + */ + if (tracepoint_destructors_syms_ptr->tracepoint_get_destructors_state + && !tracepoint_destructors_syms_ptr->tracepoint_get_destructors_state()) { + /* + * The tracepoint_get_destructors_state symbol was found with + * dlsym but its returned value is 0 meaning that destructors + * must not be executed. + */ + return; + } + /* + * Lookup if destructors must be executed using the old method. + */ + if (tracepoint_destructors_syms_ptr->old_tracepoint_disable_destructors + && *tracepoint_destructors_syms_ptr->old_tracepoint_disable_destructors) { + /* + * The old_tracepoint_disable_destructors symbol was found with + * dlsym but its value is 1 meaning that destructors must not + * be executed. + */ + return; } -} -#endif + ret = dlclose(tracepoint_dlopen_ptr->liblttngust_handle); + if (ret) { + fprintf(stderr, "Error (%d) in dlclose\n", ret); + abort(); + } + memset(tracepoint_dlopen_ptr, 0, sizeof(*tracepoint_dlopen_ptr)); +} #ifdef TRACEPOINT_DEFINE @@ -289,9 +397,9 @@ __tracepoints__destroy(void) * registering only _one_ instance of the tracepoints per shared-ojbect * (or for the whole main program). */ -extern struct tracepoint * const __start___tracepoints_ptrs[] +extern struct lttng_ust_tracepoint * const __start___tracepoints_ptrs[] __attribute__((weak, visibility("hidden"))); -extern struct tracepoint * const __stop___tracepoints_ptrs[] +extern struct lttng_ust_tracepoint * const __stop___tracepoints_ptrs[] __attribute__((weak, visibility("hidden"))); /* @@ -321,7 +429,7 @@ extern struct tracepoint * const __stop___tracepoints_ptrs[] static const char __tp_strtab_##_provider##___##_name[] \ __attribute__((section("__tracepoints_strings"))) = \ #_provider ":" #_name; \ - struct tracepoint __tracepoint_##_provider##___##_name \ + struct lttng_ust_tracepoint __tracepoint_##_provider##___##_name \ __attribute__((section("__tracepoints"))) = \ { \ __tp_strtab_##_provider##___##_name, \ @@ -329,8 +437,10 @@ extern struct tracepoint * const __stop___tracepoints_ptrs[] NULL, \ _TRACEPOINT_UNDEFINED_REF(_provider), \ _TP_EXTRACT_STRING(_args), \ + { }, \ }; \ - static struct tracepoint * __tracepoint_ptr_##_provider##___##_name \ + static struct lttng_ust_tracepoint * \ + __tracepoint_ptr_##_provider##___##_name \ __attribute__((used, section("__tracepoints_ptrs"))) = \ &__tracepoint_##_provider##___##_name; @@ -341,14 +451,41 @@ __tracepoints__ptrs_init(void) { if (__tracepoint_ptrs_registered++) return; - if (!tracepoint_dlopen.liblttngust_handle) - tracepoint_dlopen.liblttngust_handle = + if (!tracepoint_dlopen_ptr) + tracepoint_dlopen_ptr = &tracepoint_dlopen; + if (!tracepoint_dlopen_ptr->liblttngust_handle) + tracepoint_dlopen_ptr->liblttngust_handle = dlopen("liblttng-ust-tracepoint.so.0", RTLD_NOW | RTLD_GLOBAL); - if (!tracepoint_dlopen.liblttngust_handle) + if (!tracepoint_dlopen_ptr->liblttngust_handle) return; - tracepoint_dlopen.tracepoint_register_lib(__start___tracepoints_ptrs, + if (!tracepoint_destructors_syms_ptr) + tracepoint_destructors_syms_ptr = &tracepoint_destructors_syms; + tracepoint_dlopen_ptr->tracepoint_register_lib = + URCU_FORCE_CAST(int (*)(struct lttng_ust_tracepoint * const *, int), + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "tracepoint_register_lib")); + tracepoint_dlopen_ptr->tracepoint_unregister_lib = + URCU_FORCE_CAST(int (*)(struct lttng_ust_tracepoint * const *), + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "tracepoint_unregister_lib")); + tracepoint_destructors_syms_ptr->old_tracepoint_disable_destructors = + URCU_FORCE_CAST(int *, + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "__tracepoints__disable_destructors")); + tracepoint_destructors_syms_ptr->tracepoint_disable_destructors = + URCU_FORCE_CAST(void (*)(void), + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "tp_disable_destructors")); + tracepoint_destructors_syms_ptr->tracepoint_get_destructors_state = + URCU_FORCE_CAST(int (*)(void), + dlsym(tracepoint_dlopen_ptr->liblttngust_handle, + "tp_get_destructors_state")); + __tracepoint__init_urcu_sym(); + if (tracepoint_dlopen_ptr->tracepoint_register_lib) { + tracepoint_dlopen_ptr->tracepoint_register_lib(__start___tracepoints_ptrs, __stop___tracepoints_ptrs - __start___tracepoints_ptrs); + } } static void lttng_ust_notrace __attribute__((destructor)) @@ -360,12 +497,22 @@ __tracepoints__ptrs_destroy(void) if (--__tracepoint_ptrs_registered) return; - if (tracepoint_dlopen.tracepoint_unregister_lib) - tracepoint_dlopen.tracepoint_unregister_lib(__start___tracepoints_ptrs); - if (tracepoint_dlopen.liblttngust_handle && !__tracepoint_registered) { - ret = dlclose(tracepoint_dlopen.liblttngust_handle); - assert(!ret); - memset(&tracepoint_dlopen, 0, sizeof(tracepoint_dlopen)); + if (!tracepoint_dlopen_ptr) + tracepoint_dlopen_ptr = &tracepoint_dlopen; + if (!tracepoint_destructors_syms_ptr) + tracepoint_destructors_syms_ptr = &tracepoint_destructors_syms; + if (tracepoint_dlopen_ptr->tracepoint_unregister_lib) + tracepoint_dlopen_ptr->tracepoint_unregister_lib(__start___tracepoints_ptrs); + if (tracepoint_dlopen_ptr->liblttngust_handle + && tracepoint_destructors_syms_ptr->tracepoint_get_destructors_state + && tracepoint_destructors_syms_ptr->tracepoint_get_destructors_state() + && !__tracepoint_ptrs_registered) { + ret = dlclose(tracepoint_dlopen_ptr->liblttngust_handle); + if (ret) { + fprintf(stderr, "Error (%d) in dlclose\n", ret); + abort(); + } + memset(tracepoint_dlopen_ptr, 0, sizeof(*tracepoint_dlopen_ptr)); } } @@ -383,6 +530,50 @@ __tracepoints__ptrs_destroy(void) /* The following declarations must be outside re-inclusion protection. */ +#ifndef TRACEPOINT_ENUM + +/* + * Tracepoint Enumerations + * + * The enumeration is a mapping between an integer, or range of integers, and + * a string. It can be used to have a more compact trace in cases where the + * possible values for a field are limited: + * + * An example: + * + * TRACEPOINT_ENUM(someproject_component, enumname, + * TP_ENUM_VALUES( + * ctf_enum_value("even", 0) + * ctf_enum_value("uneven", 1) + * ctf_enum_range("twoto4", 2, 4) + * ctf_enum_value("five", 5) + * ) + * ) + * + * Where "someproject_component" is the name of the component this enumeration + * belongs to and "enumname" identifies this enumeration. Inside the + * TP_ENUM_VALUES macro is the actual mapping. Each string value can map + * to either a single value with ctf_enum_value or a range of values + * with ctf_enum_range. + * + * Enumeration ranges may overlap, but the behavior is implementation-defined, + * each trace reader will handle overlapping as it wishes. + * + * That enumeration can then be used in a field inside the TP_FIELD macro using + * the following line: + * + * ctf_enum(someproject_component, enumname, enumtype, enumfield, enumval) + * + * Where "someproject_component" and "enumname" match those in the + * TRACEPOINT_ENUM, "enumtype" is a signed or unsigned integer type + * backing the enumeration, "enumfield" is the name of the field and + * "enumval" is the value. + */ + +#define TRACEPOINT_ENUM(provider, name, values) + +#endif /* #ifndef TRACEPOINT_ENUM */ + #ifndef TRACEPOINT_EVENT /* @@ -406,6 +597,9 @@ __tracepoints__ptrs_destroy(void) * * Integer, printed with 0x base 16 * * ctf_integer_hex(unsigned long, field_d, arg1) * + * * Enumeration * + * ctf_enum(someproject_component, enum_name, int, field_e, arg0) + * * * Array Sequence, printed as UTF8-encoded array of bytes * * ctf_array_text(char, field_b, string, FIXED_LEN) * ctf_sequence_text(char, field_c, string, size_t, strlen) @@ -533,7 +727,7 @@ __tracepoints__ptrs_destroy(void) * debug information with line-level scope (TRACEPOINT_EVENT default) * * TRACE_DEBUG 14 - * debug-level message (trace_printf default) + * debug-level message * * Declare tracepoint loglevels for tracepoints. A TRACEPOINT_EVENT * should be declared prior to the the TRACEPOINT_LOGLEVEL for a given