#include <lttng/tracepoint-rcu.h>
#include <urcu/compiler.h>
#include <dlfcn.h> /* for dlopen */
+#include <string.h> /* for memset */
#include <assert.h>
+#include <lttng/ust-config.h> /* for sdt */
+
+#ifdef LTTNG_UST_HAVE_SDT_INTEGRATION
+#define SDT_USE_VARIADIC
+#include <sys/sdt.h>
+#else
+#define STAP_PROBEV(...)
+#endif
#ifdef __cplusplus
extern "C" {
#define tracepoint(provider, name, ...) \
do { \
+ STAP_PROBEV(provider, name, ## __VA_ARGS__); \
if (caa_unlikely(__tracepoint_##provider##___##name.state)) \
__tracepoint_cb_##provider##___##name(__VA_ARGS__); \
} while (0)
#define _TP_ARGS_DATA_VAR(...) _TP_DATA_VAR_N(_TP_NARGS(0, ##__VA_ARGS__), ##__VA_ARGS__)
#define _TP_PARAMS(...) __VA_ARGS__
-#define _DECLARE_TRACEPOINT(provider, name, ...) \
-extern struct tracepoint __tracepoint_##provider##___##name; \
-static inline void __tracepoint_cb_##provider##___##name(_TP_ARGS_PROTO(__VA_ARGS__)) \
+#define _DECLARE_TRACEPOINT(_provider, _name, ...) \
+extern struct tracepoint __tracepoint_##_provider##___##_name; \
+static inline void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)) \
{ \
struct tracepoint_probe *__tp_probe; \
\
if (!TP_RCU_LINK_TEST()) \
return; \
tp_rcu_read_lock_bp(); \
- __tp_probe = tp_rcu_dereference_bp(__tracepoint_##provider##___##name.probes); \
+ __tp_probe = tp_rcu_dereference_bp(__tracepoint_##_provider##___##_name.probes); \
if (caa_unlikely(!__tp_probe)) \
goto end; \
do { \
end: \
tp_rcu_read_unlock_bp(); \
} \
-static inline void __tracepoint_register_##provider##___##name(char *name, \
+static inline void __tracepoint_register_##_provider##___##_name(char *name, \
void *func, void *data) \
{ \
- __tracepoint_probe_register(name, func, data); \
+ __tracepoint_probe_register(name, func, data, \
+ __tracepoint_##_provider##___##_name.signature); \
} \
-static inline void __tracepoint_unregister_##provider##___##name(char *name, \
+static inline void __tracepoint_unregister_##_provider##___##_name(char *name, \
void *func, void *data) \
{ \
__tracepoint_probe_unregister(name, func, data); \
}
-extern int __tracepoint_probe_register(const char *name, void *func, void *data);
+extern int __tracepoint_probe_register(const char *name, void *func, void *data,
+ const char *signature);
extern int __tracepoint_probe_unregister(const char *name, void *func, void *data);
+/*
+ * tracepoint dynamic linkage handling (callbacks). Hidden visibility:
+ * shared across objects in a module/main executable.
+ */
+struct tracepoint_dlopen {
+ void *liblttngust_handle;
+
+ int (*tracepoint_register_lib)(struct tracepoint * const *tracepoints_start,
+ int tracepoints_count);
+ int (*tracepoint_unregister_lib)(struct tracepoint * const *tracepoints_start);
+#ifndef _LGPL_SOURCE
+ 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;
+
#ifdef TRACEPOINT_DEFINE
+/*
+ * When TRACEPOINT_PROBE_DYNAMIC_LINKAGE is defined, we do not emit a
+ * unresolved symbol that requires the provider to be linked in. When
+ * TRACEPOINT_PROBE_DYNAMIC_LINKAGE is not defined, we emit an
+ * unresolved symbol that depends on having the provider linked in,
+ * otherwise the linker complains. This deals with use of static
+ * libraries, ensuring that the linker does not remove the provider
+ * object from the executable.
+ */
+#ifdef TRACEPOINT_PROBE_DYNAMIC_LINKAGE
+#define _TRACEPOINT_UNDEFINED_REF(provider) NULL
+#else /* TRACEPOINT_PROBE_DYNAMIC_LINKAGE */
+#define _TRACEPOINT_UNDEFINED_REF(provider) &__tracepoint_provider_##provider
+#endif /* TRACEPOINT_PROBE_DYNAMIC_LINKAGE */
+
/*
* Note: to allow PIC code, we need to allow the linker to update the pointers
* in the __tracepoints_ptrs section.
* Therefore, this section is _not_ const (read-only).
*/
-#define _DEFINE_TRACEPOINT(provider, name) \
- static const char __tp_strtab_##provider##___##name[] \
+#define _TP_EXTRACT_STRING(...) #__VA_ARGS__
+
+#define _DEFINE_TRACEPOINT(_provider, _name, _args) \
+ extern int __tracepoint_provider_##_provider; \
+ static const char __tp_strtab_##_provider##___##_name[] \
__attribute__((section("__tracepoints_strings"))) = \
- #provider ":" #name; \
- struct tracepoint __tracepoint_##provider##___##name \
+ #_provider ":" #_name; \
+ struct tracepoint __tracepoint_##_provider##___##_name \
__attribute__((section("__tracepoints"))) = \
- { __tp_strtab_##provider##___##name, 0, NULL }; \
- static struct tracepoint * __tracepoint_ptr_##provider##___##name \
+ { \
+ __tp_strtab_##_provider##___##_name, \
+ 0, \
+ NULL, \
+ _TRACEPOINT_UNDEFINED_REF(_provider), \
+ _TP_EXTRACT_STRING(_args), \
+ }; \
+ static struct tracepoint * __tracepoint_ptr_##_provider##___##_name \
__attribute__((used, section("__tracepoints_ptrs"))) = \
- &__tracepoint_##provider##___##name;
-
-static int (*tracepoint_register_lib)(struct tracepoint * const *tracepoints_start,
- int tracepoints_count);
-static int (*tracepoint_unregister_lib)(struct tracepoint * const *tracepoints_start);
-static void *liblttngust_handle;
+ &__tracepoint_##_provider##___##_name;
/*
* These weak symbols, the constructor, and destructor take care of
__attribute__((weak, visibility("hidden")));
int __tracepoint_registered
__attribute__((weak, visibility("hidden")));
+struct tracepoint_dlopen tracepoint_dlopen
+ __attribute__((weak, visibility("hidden")));
static void __attribute__((constructor)) __tracepoints__init(void)
{
if (__tracepoint_registered++)
return;
- liblttngust_handle = dlopen("liblttng-ust-tracepoint.so.0", RTLD_NOW | RTLD_GLOBAL);
- if (!liblttngust_handle)
+ tracepoint_dlopen.liblttngust_handle =
+ dlopen("liblttng-ust-tracepoint.so.0", RTLD_NOW | RTLD_GLOBAL);
+ if (!tracepoint_dlopen.liblttngust_handle)
return;
- tracepoint_register_lib =
+ tracepoint_dlopen.tracepoint_register_lib =
URCU_FORCE_CAST(int (*)(struct tracepoint * const *, int),
- dlsym(liblttngust_handle,
+ dlsym(tracepoint_dlopen.liblttngust_handle,
"tracepoint_register_lib"));
- tracepoint_unregister_lib =
+ tracepoint_dlopen.tracepoint_unregister_lib =
URCU_FORCE_CAST(int (*)(struct tracepoint * const *),
- dlsym(liblttngust_handle,
+ dlsym(tracepoint_dlopen.liblttngust_handle,
"tracepoint_unregister_lib"));
#ifndef _LGPL_SOURCE
- tp_rcu_read_lock_bp =
+ tracepoint_dlopen.rcu_read_lock_sym_bp =
URCU_FORCE_CAST(void (*)(void),
- dlsym(liblttngust_handle,
+ dlsym(tracepoint_dlopen.liblttngust_handle,
"tp_rcu_read_lock_bp"));
- tp_rcu_read_unlock_bp =
+ tracepoint_dlopen.rcu_read_unlock_sym_bp =
URCU_FORCE_CAST(void (*)(void),
- dlsym(liblttngust_handle,
+ dlsym(tracepoint_dlopen.liblttngust_handle,
"tp_rcu_read_unlock_bp"));
- tp_rcu_dereference_sym_bp =
+ tracepoint_dlopen.rcu_dereference_sym_bp =
URCU_FORCE_CAST(void *(*)(void *p),
- dlsym(liblttngust_handle,
+ dlsym(tracepoint_dlopen.liblttngust_handle,
"tp_rcu_dereference_sym_bp"));
#endif
- tracepoint_register_lib(__start___tracepoints_ptrs,
+ tracepoint_dlopen.tracepoint_register_lib(__start___tracepoints_ptrs,
__stop___tracepoints_ptrs -
__start___tracepoints_ptrs);
}
static void __attribute__((destructor)) __tracepoints__destroy(void)
{
int ret;
+
if (--__tracepoint_registered)
return;
- if (tracepoint_unregister_lib)
- tracepoint_unregister_lib(__start___tracepoints_ptrs);
- if (liblttngust_handle) {
- tracepoint_unregister_lib = NULL;
- tracepoint_register_lib = NULL;
- ret = dlclose(liblttngust_handle);
+ if (tracepoint_dlopen.tracepoint_unregister_lib)
+ tracepoint_dlopen.tracepoint_unregister_lib(__start___tracepoints_ptrs);
+ if (tracepoint_dlopen.liblttngust_handle) {
+ ret = dlclose(tracepoint_dlopen.liblttngust_handle);
assert(!ret);
+ memset(&tracepoint_dlopen, 0, sizeof(tracepoint_dlopen));
}
}
#else /* TRACEPOINT_DEFINE */
-#define _DEFINE_TRACEPOINT(provider, name)
+#define _DEFINE_TRACEPOINT(_provider, _name, _args)
#endif /* #else TRACEPOINT_DEFINE */
#define TRACEPOINT_EVENT(provider, name, args, fields) \
_DECLARE_TRACEPOINT(provider, name, _TP_PARAMS(args)) \
- _DEFINE_TRACEPOINT(provider, name)
+ _DEFINE_TRACEPOINT(provider, name, _TP_PARAMS(args))
#define TRACEPOINT_EVENT_CLASS(provider, name, args, fields)
#define TRACEPOINT_EVENT_INSTANCE(provider, _template, name, args) \
_DECLARE_TRACEPOINT(provider, name, _TP_PARAMS(args)) \
- _DEFINE_TRACEPOINT(provider, name)
+ _DEFINE_TRACEPOINT(provider, name, _TP_PARAMS(args))
#endif /* #ifndef TRACEPOINT_EVENT */
*
* Typical use of these loglevels:
*
- * The loglevels go from 0 to 15. Higher numbers imply the most
+ * The loglevels go from 0 to 14. Higher numbers imply the most
* verbosity (higher event throughput expected.
*
- * Loglevels 0 through 6, and loglevel 15, match syslog(3) loglevels
- * semantic. Loglevels 7 through 14 offer more fine-grained selection of
- * traced information.
+ * Loglevels 0 through 6, and loglevel 14, match syslog(3) loglevels
+ * semantic. Loglevels 7 through 13 offer more fine-grained selection of
+ * debug information.
*
- * TRACE_EMERG 0
+ * TRACE_EMERG 0
* system is unusable
*
- * TRACE_ALERT 1
+ * TRACE_ALERT 1
* action must be taken immediately
*
- * TRACE_CRIT 2
+ * TRACE_CRIT 2
* critical conditions
*
- * TRACE_ERR 3
+ * TRACE_ERR 3
* error conditions
*
- * TRACE_WARNING 4
+ * TRACE_WARNING 4
* warning conditions
*
- * TRACE_NOTICE 5
+ * TRACE_NOTICE 5
* normal, but significant, condition
*
- * TRACE_INFO 6
+ * TRACE_INFO 6
* informational message
*
- * TRACE_SYSTEM 7
- * information has system-level scope
- *
- * TRACE_PROCESS 8
- * information has process-level scope
+ * TRACE_DEBUG_SYSTEM 7
+ * debug information with system-level scope (set of programs)
*
- * TRACE_MODULE 9
- * information has module (executable/library) scope
+ * TRACE_DEBUG_PROGRAM 8
+ * debug information with program-level scope (set of processes)
*
- * TRACE_UNIT 10
- * information has compilation unit scope
+ * TRACE_DEBUG_PROCESS 9
+ * debug information with process-level scope (set of modules)
*
- * TRACE_CLASS 11
- * information has class-level scope
+ * TRACE_DEBUG_MODULE 10
+ * debug information with module (executable/library) scope (set of units)
*
- * TRACE_OBJECT 12
- * information has object-level scope
+ * TRACE_DEBUG_UNIT 11
+ * debug information with compilation unit scope (set of functions)
*
- * TRACE_FUNCTION 13
- * information has function-level scope
+ * TRACE_DEBUG_FUNCTION 12
+ * debug information with function-level scope
*
- * TRACE_PRINTF 14
- * tracepoint_printf message
+ * TRACE_DEBUG_LINE 13
+ * debug information with line-level scope (TRACEPOINT_EVENT default)
*
- * TRACE_DEBUG 15
- * debug-level message
+ * TRACE_DEBUG 14
+ * debug-level message (trace_printf default)
*
* Declare tracepoint loglevels for tracepoints. A TRACEPOINT_EVENT
* should be declared prior to the the TRACEPOINT_LOGLEVEL for a given
- * tracepoint name. The first field is the name of the tracepoint, the
- * second field is the loglevel name.
+ * tracepoint name. The first field is the provider name, the second
+ * field is the name of the tracepoint, the third field is the loglevel
+ * name.
*
* TRACEPOINT_LOGLEVEL(< [com_company_]project[_component] >, < event >,
* < loglevel_name >)
*/
enum {
- TRACE_EMERG = 0,
- TRACE_ALERT = 1,
- TRACE_CRIT = 2,
- TRACE_ERR = 3,
- TRACE_WARNING = 4,
- TRACE_NOTICE = 5,
- TRACE_INFO = 6,
- TRACE_SYSTEM = 7,
- TRACE_PROCESS = 8,
- TRACE_MODULE = 9,
- TRACE_UNIT = 10,
- TRACE_CLASS = 11,
- TRACE_OBJECT = 12,
- TRACE_FUNCTION = 13,
- TRACE_PRINTF = 14,
- TRACE_DEBUG = 15,
+ TRACE_EMERG = 0,
+ TRACE_ALERT = 1,
+ TRACE_CRIT = 2,
+ TRACE_ERR = 3,
+ TRACE_WARNING = 4,
+ TRACE_NOTICE = 5,
+ TRACE_INFO = 6,
+ TRACE_DEBUG_SYSTEM = 7,
+ TRACE_DEBUG_PROGRAM = 8,
+ TRACE_DEBUG_PROCESS = 9,
+ TRACE_DEBUG_MODULE = 10,
+ TRACE_DEBUG_UNIT = 11,
+ TRACE_DEBUG_FUNCTION = 12,
+ TRACE_DEBUG_LINE = 13,
+ TRACE_DEBUG = 14,
};
#define TRACEPOINT_LOGLEVEL(provider, name, loglevel)