X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=include%2Flttng%2Ftracepoint.h;h=269bb2b23ecc8e369a7da1167b34e143ab621572;hb=cadfcbfcd89795086bfeb49af84dadc35154c754;hp=d77a2fb298c40f99c7fd290eb48eda48d36bcae9;hpb=0fd0de100bc6633e8ecf575301dc92321db32575;p=lttng-ust.git diff --git a/include/lttng/tracepoint.h b/include/lttng/tracepoint.h index d77a2fb2..269bb2b2 100644 --- a/include/lttng/tracepoint.h +++ b/include/lttng/tracepoint.h @@ -1,28 +1,12 @@ -#ifndef _LTTNG_TRACEPOINT_H -#define _LTTNG_TRACEPOINT_H - /* - * Copyright 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. + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2011-2012 Mathieu Desnoyers */ +#ifndef _LTTNG_TRACEPOINT_H +#define _LTTNG_TRACEPOINT_H + #include #include #include @@ -31,38 +15,58 @@ #include #include /* for dlopen */ #include /* for memset */ + #include /* for sdt */ #include +#include +#include + +#define LTTNG_UST_TRACEPOINT_NAME_LEN_MAX 256 #ifdef LTTNG_UST_HAVE_SDT_INTEGRATION -#define SDT_USE_VARIADIC +/* + * Instead of using SDT_USE_VARIADIC from 'sys/sdt.h', use our own namespaced + * macros since the instrumented application might already have included + * 'sys/sdt.h' without variadic support. + */ #include -#define LTTNG_STAP_PROBEV STAP_PROBEV + +#define _LTTNG_UST_SDT_NARG(...) \ + __LTTNG_UST_SDT_NARG(__VA_ARGS__, 12,11,10,9,8,7,6,5,4,3,2,1,0) + +#define __LTTNG_UST_SDT_NARG(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12, N, ...) N + +#define _LTTNG_UST_SDT_PROBE_N(provider, name, N, ...) \ + _SDT_PROBE(provider, name, N, (__VA_ARGS__)) + +#define LTTNG_UST_STAP_PROBEV(provider, name, ...) \ + _LTTNG_UST_SDT_PROBE_N(provider, name, _LTTNG_UST_SDT_NARG(0, ##__VA_ARGS__), ##__VA_ARGS__) + #else -#define LTTNG_STAP_PROBEV(...) +#define LTTNG_UST_STAP_PROBEV(...) #endif #ifdef __cplusplus extern "C" { #endif -#define tracepoint_enabled(provider, name) \ +#define lttng_ust_tracepoint_enabled(provider, name) \ caa_unlikely(CMM_LOAD_SHARED(__tracepoint_##provider##___##name.state)) -#define do_tracepoint(provider, name, ...) \ +#define lttng_ust_do_tracepoint(provider, name, ...) \ __tracepoint_cb_##provider##___##name(__VA_ARGS__) -#define tracepoint(provider, name, ...) \ - do { \ - LTTNG_STAP_PROBEV(provider, name, ## __VA_ARGS__); \ - if (tracepoint_enabled(provider, name)) \ - do_tracepoint(provider, name, __VA_ARGS__); \ +#define lttng_ust_tracepoint(provider, name, ...) \ + do { \ + LTTNG_UST_STAP_PROBEV(provider, name, ## __VA_ARGS__); \ + if (lttng_ust_tracepoint_enabled(provider, name)) \ + lttng_ust_do_tracepoint(provider, name, __VA_ARGS__); \ } while (0) -#define TP_ARGS(...) __VA_ARGS__ +#define LTTNG_UST_TP_ARGS(...) __VA_ARGS__ /* - * TP_ARGS takes tuples of type, argument separated by a comma. + * LTTNG_UST_TP_ARGS takes tuples of type, argument separated by a comma. * It can take up to 10 tuples (which means that less than 10 tuples is * fine too). * Each tuple is also separated by a comma. @@ -153,6 +157,25 @@ extern "C" { #define _TP_ARGS_DATA_VAR(...) _TP_DATA_VAR_N(_TP_NARGS(0, ##__VA_ARGS__), ##__VA_ARGS__) #define _TP_PARAMS(...) __VA_ARGS__ +/* + * sizeof(#_provider) - 1 : length of the provider string (excluding \0). + * sizeof(#_name) - 1 : length of the name string (excluding \0). + * + 1 : separator between provider and event name. + * + * Upper bound (inclusive) is LTTNG_UST_TRACEPOINT_NAME_LEN_MAX - 1 to + * account for \0. + * + * The comparison is: + * left hand side: sizeof(#_provider) - 1 + sizeof(#_name) - 1 + 1 + * right hand side: LTTNG_UST_TRACEPOINT_NAME_LEN_MAX - 1 + * operator: <= (inclusive) + * Simplified in the code below. + */ +#define lttng_ust_tracepoint_validate_name_len(_provider, _name) \ + lttng_ust_static_assert(sizeof(#_provider) + sizeof(#_name) <= LTTNG_UST_TRACEPOINT_NAME_LEN_MAX, \ + "Tracepoint name length is too long", \ + Tracepoint_name_length_is_too_long) + /* * The tracepoint cb is marked always inline so we can distinguish * between caller's ip addresses within the probe using the return @@ -160,17 +183,18 @@ extern "C" { */ #define _DECLARE_TRACEPOINT(_provider, _name, ...) \ 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 \ +void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)) \ + __attribute__((always_inline, unused)) lttng_ust_notrace; \ static \ void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)) \ { \ - struct lttng_ust_tracepoint_probe *__tp_probe; \ + struct lttng_ust_tracepoint_probe *__tp_probe; \ \ if (caa_unlikely(!TP_RCU_LINK_TEST())) \ return; \ - tp_rcu_read_lock_bp(); \ - __tp_probe = tp_rcu_dereference_bp(__tracepoint_##_provider##___##_name.probes); \ + tp_rcu_read_lock(); \ + __tp_probe = tp_rcu_dereference(__tracepoint_##_provider##___##_name.probes); \ if (caa_unlikely(!__tp_probe)) \ goto end; \ do { \ @@ -181,46 +205,60 @@ void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)) \ (_TP_ARGS_DATA_VAR(__VA_ARGS__)); \ } while ((++__tp_probe)->func); \ end: \ - tp_rcu_read_unlock_bp(); \ + tp_rcu_read_unlock(); \ } \ -static inline lttng_ust_notrace \ -void __tracepoint_register_##_provider##___##_name(char *name, \ - void (*func)(void), void *data); \ static inline \ -void __tracepoint_register_##_provider##___##_name(char *name, \ +void __tracepoint_register_##_provider##___##_name(char *provider_name, char *event_name, \ + void (*func)(void), void *data) \ + lttng_ust_notrace; \ +static inline \ +void __tracepoint_register_##_provider##___##_name(char *provider_name, char *event_name, \ void (*func)(void), void *data) \ { \ - __tracepoint_probe_register(name, func, data, \ + __tracepoint_probe_register(provider_name, event_name, func, data, \ __tracepoint_##_provider##___##_name.signature); \ } \ -static inline lttng_ust_notrace \ -void __tracepoint_unregister_##_provider##___##_name(char *name, \ - void (*func)(void), void *data); \ static inline \ -void __tracepoint_unregister_##_provider##___##_name(char *name, \ +void __tracepoint_unregister_##_provider##___##_name(char *provider_name, char *event_name, \ + void (*func)(void), void *data) \ + lttng_ust_notrace; \ +static inline \ +void __tracepoint_unregister_##_provider##___##_name(char *provider_name, char *event_name, \ void (*func)(void), void *data) \ { \ - __tracepoint_probe_unregister(name, func, data); \ + __tracepoint_probe_unregister(provider_name, event_name, func, data); \ } -extern int __tracepoint_probe_register(const char *name, void (*func)(void), - void *data, const char *signature); -extern int __tracepoint_probe_unregister(const char *name, void (*func)(void), - void *data); +extern int __tracepoint_probe_register(const char *provider_name, const char *event_name, + void (*func)(void), void *data, const char *signature); +extern int __tracepoint_probe_unregister(const char *provider_name, const char *event_name, + void (*func)(void), void *data); /* * tracepoint dynamic linkage handling (callbacks). Hidden visibility: * shared across objects in a module/main executable. + * + * IMPORTANT: this structure is part of the ABI between instrumented + * applications and UST. Fields need to be only added at the end, never + * reordered, never removed. + * + * The field @struct_size should be used to determine the size of the + * structure. It should be queried before using additional fields added + * at the end of the structure. */ struct lttng_ust_tracepoint_dlopen { + uint32_t struct_size; + void *liblttngust_handle; int (*tracepoint_register_lib)(struct lttng_ust_tracepoint * const *tracepoints_start, int tracepoints_count); 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); + void (*rcu_read_lock_sym)(void); + void (*rcu_read_unlock_sym)(void); + void *(*rcu_dereference_sym)(void *p); + + /* End of base ABI. Fields below should be used after checking struct_size. */ }; extern struct lttng_ust_tracepoint_dlopen tracepoint_dlopen; @@ -236,7 +274,9 @@ int __tracepoint_registered int __tracepoint_ptrs_registered __attribute__((weak, visibility("hidden"))); struct lttng_ust_tracepoint_dlopen tracepoint_dlopen - __attribute__((weak, visibility("hidden"))); + __attribute__((weak, visibility("hidden"))) = { + .struct_size = sizeof(struct lttng_ust_tracepoint_dlopen), +}; /* * 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 @@ -254,18 +294,31 @@ struct lttng_ust_tracepoint_dlopen *tracepoint_dlopen_ptr * 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. + * + * IMPORTANT: this structure is part of the ABI between instrumented + * applications and UST. Fields need to be only added at the end, never + * reordered, never removed. + * + * The field @struct_size should be used to determine the size of the + * structure. It should be queried before using additional fields added + * at the end of the structure. */ struct lttng_ust_tracepoint_destructors_syms { - int *old_tracepoint_disable_destructors; + uint32_t struct_size; + void (*tracepoint_disable_destructors)(void); int (*tracepoint_get_destructors_state)(void); + + /* End of base ABI. Fields below should be used after checking struct_size. */ }; 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"))); + __attribute__((weak, visibility("hidden"))) = { + .struct_size = sizeof(struct lttng_ust_tracepoint_destructors_syms), +}; struct lttng_ust_tracepoint_destructors_syms *tracepoint_destructors_syms_ptr __attribute__((weak, visibility("hidden"))); @@ -278,12 +331,12 @@ static inline void tracepoint_disable_destructors(void) 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) + lttng_ust_notrace; static inline void __tracepoint__init_urcu_sym(void) { @@ -293,33 +346,35 @@ __tracepoint__init_urcu_sym(void) * 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 = + if (!tracepoint_dlopen_ptr->rcu_read_lock_sym) + tracepoint_dlopen_ptr->rcu_read_lock_sym = 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 = + "tp_rcu_read_lock")); + if (!tracepoint_dlopen_ptr->rcu_read_unlock_sym) + tracepoint_dlopen_ptr->rcu_read_unlock_sym = 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 = + "tp_rcu_read_unlock")); + if (!tracepoint_dlopen_ptr->rcu_dereference_sym) + tracepoint_dlopen_ptr->rcu_dereference_sym = URCU_FORCE_CAST(void *(*)(void *p), dlsym(tracepoint_dlopen_ptr->liblttngust_handle, - "tp_rcu_dereference_sym_bp")); + "tp_rcu_dereference_sym")); } #else -static inline void lttng_ust_notrace -__tracepoint__init_urcu_sym(void); +static inline void +__tracepoint__init_urcu_sym(void) + lttng_ust_notrace; static inline void __tracepoint__init_urcu_sym(void) { } #endif -static void lttng_ust_notrace __attribute__((constructor)) -__tracepoints__init(void); +static void +__tracepoints__init(void) + lttng_ust_notrace __attribute__((constructor)); static void __tracepoints__init(void) { @@ -334,14 +389,15 @@ __tracepoints__init(void) 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); + dlopen(LTTNG_UST_TRACEPOINT_LIB_SONAME, RTLD_NOW | RTLD_GLOBAL); if (!tracepoint_dlopen_ptr->liblttngust_handle) return; __tracepoint__init_urcu_sym(); } -static void lttng_ust_notrace __attribute__((destructor)) -__tracepoints__destroy(void); +static void +__tracepoints__destroy(void) + lttng_ust_notrace __attribute__((destructor)); static void __tracepoints__destroy(void) { @@ -369,19 +425,6 @@ __tracepoints__destroy(void) */ 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; - } - ret = dlclose(tracepoint_dlopen_ptr->liblttngust_handle); if (ret) { fprintf(stderr, "Error (%d) in dlclose\n", ret); @@ -425,27 +468,33 @@ extern struct lttng_ust_tracepoint * const __stop___tracepoints_ptrs[] #define _TP_EXTRACT_STRING(...) #__VA_ARGS__ #define _DEFINE_TRACEPOINT(_provider, _name, _args) \ + lttng_ust_tracepoint_validate_name_len(_provider, _name); \ extern int __tracepoint_provider_##_provider; \ - static const char __tp_strtab_##_provider##___##_name[] \ + static const char __tp_provider_strtab_##_provider##___##_name[] \ + __attribute__((section("__tracepoints_strings"))) = \ + #_provider; \ + static const char __tp_name_strtab_##_provider##___##_name[] \ __attribute__((section("__tracepoints_strings"))) = \ - #_provider ":" #_name; \ + #_name; \ struct lttng_ust_tracepoint __tracepoint_##_provider##___##_name \ - __attribute__((section("__tracepoints"))) = \ - { \ - __tp_strtab_##_provider##___##_name, \ + __attribute__((section("__tracepoints"))) = { \ + sizeof(struct lttng_ust_tracepoint), \ + __tp_provider_strtab_##_provider##___##_name, \ + __tp_name_strtab_##_provider##___##_name, \ 0, \ NULL, \ _TRACEPOINT_UNDEFINED_REF(_provider), \ _TP_EXTRACT_STRING(_args), \ - { }, \ }; \ static struct lttng_ust_tracepoint * \ __tracepoint_ptr_##_provider##___##_name \ - __attribute__((used, section("__tracepoints_ptrs"))) = \ + __attribute__((section("__tracepoints_ptrs"), used)) \ + __lttng_ust_variable_attribute_no_sanitize_address = \ &__tracepoint_##_provider##___##_name; -static void lttng_ust_notrace __attribute__((constructor)) -__tracepoints__ptrs_init(void); +static void +__tracepoints__ptrs_init(void) + lttng_ust_notrace __attribute__((constructor)); static void __tracepoints__ptrs_init(void) { @@ -455,7 +504,7 @@ __tracepoints__ptrs_init(void) 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); + dlopen(LTTNG_UST_TRACEPOINT_LIB_SONAME, RTLD_NOW | RTLD_GLOBAL); if (!tracepoint_dlopen_ptr->liblttngust_handle) return; if (!tracepoint_destructors_syms_ptr) @@ -468,10 +517,6 @@ __tracepoints__ptrs_init(void) 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, @@ -488,8 +533,9 @@ __tracepoints__ptrs_init(void) } } -static void lttng_ust_notrace __attribute__((destructor)) -__tracepoints__ptrs_destroy(void); +static void +__tracepoints__ptrs_destroy(void) + lttng_ust_notrace __attribute__((destructor)); static void __tracepoints__ptrs_destroy(void) { @@ -522,6 +568,13 @@ __tracepoints__ptrs_destroy(void) #endif /* #else TRACEPOINT_DEFINE */ +#if LTTNG_UST_COMPAT_API(0) +#define tracepoint lttng_ust_tracepoint +#define do_tracepoint lttng_ust_do_tracepoint +#define tracepoint_enabled lttng_ust_tracepoint_enabled +#define TP_ARGS LTTNG_UST_TP_ARGS +#endif /* #if LTTNG_UST_COMPAT_API(0) */ + #ifdef __cplusplus } #endif @@ -580,34 +633,34 @@ __tracepoints__ptrs_destroy(void) * How to use the TRACEPOINT_EVENT macro: * * An example: - * + * * TRACEPOINT_EVENT(someproject_component, event_name, * - * * TP_ARGS takes from 0 to 10 "type, field_name" pairs * + * * LTTNG_UST_TP_ARGS takes from 0 to 10 "type, field_name" pairs * * - * TP_ARGS(int, arg0, void *, arg1, char *, string, size_t, strlen, + * LTTNG_UST_TP_ARGS(int, arg0, void *, arg1, char *, string, size_t, strlen, * long *, arg4, size_t, arg4_len), * * * TP_FIELDS describes the event payload layout in the trace * * * TP_FIELDS( - * * Integer, printed in base 10 * + * * Integer, printed in base 10 * * ctf_integer(int, field_a, arg0) * - * * Integer, printed with 0x base 16 * + * * 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 * + * * 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) * - * * String, printed as UTF8-encoded string * + * * String, printed as UTF8-encoded string * * ctf_string(field_e, string) * - * * Array sequence of signed integer values * + * * Array sequence of signed integer values * * ctf_array(long, field_f, arg4, FIXED_LEN4) * ctf_sequence(long, field_g, arg4, size_t, arg4_len) * )