#include <string.h> /* for memset */
#include <assert.h>
#include <lttng/ust-config.h> /* for sdt */
+#include <lttng/ust-compiler.h>
#ifdef LTTNG_UST_HAVE_SDT_INTEGRATION
#define SDT_USE_VARIADIC
extern "C" {
#endif
-#define tracepoint(provider, name, ...) \
- do { \
- STAP_PROBEV(provider, name, ## __VA_ARGS__); \
- if (caa_unlikely(__tracepoint_##provider##___##name.state)) \
- __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__); \
+ TRACEPOINT_CALLSITE(provider, name); \
+ } \
} while (0)
#define TP_ARGS(...) __VA_ARGS__
#define _TP_COMBINE_TOKENS4(_tokena, _tokenb, _tokenc, _tokend) \
__TP_COMBINE_TOKENS4(_tokena, _tokenb, _tokenc, _tokend)
-/* _TP_EXVAR* extract the var names. */
+/*
+ * _TP_EXVAR* extract the var names.
+ * _TP_EXVAR1 and _TP_EXDATA_VAR1 are needed for -std=c99.
+ */
#define _TP_EXVAR0()
+#define _TP_EXVAR1(a)
#define _TP_EXVAR2(a,b) b
#define _TP_EXVAR4(a,b,c,d) b,d
#define _TP_EXVAR6(a,b,c,d,e,f) b,d,f
#define _TP_EXVAR20(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t) b,d,f,h,j,l,n,p,r,t
#define _TP_EXDATA_VAR0() __tp_data
+#define _TP_EXDATA_VAR1(a) __tp_data
#define _TP_EXDATA_VAR2(a,b) __tp_data,b
#define _TP_EXDATA_VAR4(a,b,c,d) __tp_data,b,d
#define _TP_EXDATA_VAR6(a,b,c,d,e,f) __tp_data,b,d,f
#define _TP_EXDATA_VAR18(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) __tp_data,b,d,f,h,j,l,n,p,r
#define _TP_EXDATA_VAR20(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t) __tp_data,b,d,f,h,j,l,n,p,r,t
-/* _TP_EXPROTO* extract tuples of type, var */
-#define _TP_EXPROTO0()
+/*
+ * _TP_EXPROTO* extract tuples of type, var.
+ * _TP_EXPROTO1 and _TP_EXDATA_PROTO1 are needed for -std=c99.
+ */
+#define _TP_EXPROTO0() void
+#define _TP_EXPROTO1(a) void
#define _TP_EXPROTO2(a,b) a b
#define _TP_EXPROTO4(a,b,c,d) a b,c d
#define _TP_EXPROTO6(a,b,c,d,e,f) a b,c d,e f
#define _TP_EXPROTO20(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t) a b,c d,e f,g h,i j,k l,m n,o p,q r,s t
#define _TP_EXDATA_PROTO0() void *__tp_data
+#define _TP_EXDATA_PROTO1(a) void *__tp_data
#define _TP_EXDATA_PROTO2(a,b) void *__tp_data,a b
#define _TP_EXDATA_PROTO4(a,b,c,d) void *__tp_data,a b,c d
#define _TP_EXDATA_PROTO6(a,b,c,d,e,f) void *__tp_data,a b,c d,e f
#define _DECLARE_TRACEPOINT(_provider, _name, ...) \
extern struct tracepoint __tracepoint_##_provider##___##_name; \
-static inline void __tracepoint_cb_##_provider##___##_name(_TP_ARGS_PROTO(__VA_ARGS__)) \
+static inline 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__)) \
{ \
struct tracepoint_probe *__tp_probe; \
\
if (caa_unlikely(!__tp_probe)) \
goto end; \
do { \
- void *__tp_cb = __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) \
end: \
tp_rcu_read_unlock_bp(); \
} \
-static inline void __tracepoint_register_##_provider##___##_name(char *name, \
- void *func, void *data) \
+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 (*func)(void), void *data) \
{ \
__tracepoint_probe_register(name, func, data, \
__tracepoint_##_provider##___##_name.signature); \
} \
-static inline void __tracepoint_unregister_##_provider##___##_name(char *name, \
- void *func, void *data) \
+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 (*func)(void), void *data) \
{ \
__tracepoint_probe_unregister(name, func, 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);
+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);
/*
* tracepoint dynamic linkage handling (callbacks). Hidden visibility:
extern struct tracepoint_dlopen tracepoint_dlopen;
+struct tracepoint_callsite_dlopen {
+ void *liblttngust_handle;
+
+ int (*tracepoint_register_lib_callsite)(struct tracepoint_callsite * const *tp_start,
+ int tp_count);
+ int (*tracepoint_unregister_lib_callsite)(struct tracepoint_callsite * const *tp_start,
+ int tp_count);
+};
+
+struct tracepoint_callsite_dlopen tracepoint_callsite_dlopen
+ __attribute__((weak, visibility("hidden")));
+int __tracepoint_callsite_registered
+ __attribute__((weak, visibility("hidden")));
+
+#if (CAA_BITS_PER_LONG == 64)
+#define __TP_ASM_PTR ".quad "
+#else
+#define __TP_ASM_PTR ".long "
+#endif
+
+/*
+ * Note: to allow PIC code, we need to allow the linker to update the pointers
+ * in the __tracepoints_callsite_ptrs section.
+ * Therefore, this section is _not_ const (read-only).
+ */
+#define TRACEPOINT_CALLSITE(_provider, _name) \
+do { \
+ asm volatile ( ".pushsection __tracepoint_callsite, \"aw\"\n\t" \
+ "1:\n\t" \
+ __TP_ASM_PTR "%c0, %c1, %c2, 2f\n\t" \
+ ".int %c3\n\t" \
+ ".space 16\n\t" /* padding */ \
+ ".popsection\n\t" \
+ ".pushsection __tracepoint_callsite_ptrs, \"aw\"\n\t" \
+ __TP_ASM_PTR "1b\n\t" \
+ ".popsection\n\t" \
+ "2:\n\t" \
+ : : "i" (#_provider ":" #_name), \
+ "i" (__func__), \
+ "i" (__FILE__), \
+ "i" (__LINE__)); \
+} while (0)
+
+/*
+ * These weak symbols, the constructor, and destructor take care of
+ * registering only _one_ instance of the tracepoint callsite per
+ * shared-ojbect (or for the whole main program).
+ */
+extern struct tracepoint_callsite * const __start___tracepoint_callsite_ptrs[]
+ __attribute__((weak, visibility("hidden")));
+extern struct tracepoint_callsite * const __stop___tracepoint_callsite_ptrs[]
+ __attribute__((weak, visibility("hidden")));
+
+/*
+ * We need at least one pointer in the section.
+ */
+static struct tracepoint_callsite *
+ __tracepoint_callsite_ptr_dummy
+ __attribute__((used, section("__tracepoint_callsite_ptrs"))) =
+ NULL;
+
+static void lttng_ust_notrace __attribute__((constructor))
+__tracepoint_callsite__init(void);
+static void
+__tracepoint_callsite__init(void)
+{
+ if (__tracepoint_callsite_registered++)
+ return;
+
+ tracepoint_callsite_dlopen.liblttngust_handle =
+ dlopen("liblttng-ust-tracepoint.so.0", RTLD_NOW | RTLD_GLOBAL);
+ if (!tracepoint_callsite_dlopen.liblttngust_handle)
+ return;
+ tracepoint_callsite_dlopen.tracepoint_register_lib_callsite =
+ URCU_FORCE_CAST(int (*)(struct tracepoint_callsite * const *, int),
+ dlsym(tracepoint_callsite_dlopen.liblttngust_handle,
+ "tracepoint_register_lib_callsite"));
+ tracepoint_callsite_dlopen.tracepoint_unregister_lib_callsite =
+ URCU_FORCE_CAST(int (*)(struct tracepoint_callsite * const *, int),
+ dlsym(tracepoint_callsite_dlopen.liblttngust_handle,
+ "tracepoint_unregister_lib_callsite"));
+ tracepoint_callsite_dlopen.tracepoint_register_lib_callsite(__start___tracepoint_callsite_ptrs,
+ __stop___tracepoint_callsite_ptrs -
+ __start___tracepoint_callsite_ptrs);
+}
+
+static void lttng_ust_notrace __attribute__((destructor))
+__tracepoint_callsite__destroy(void);
+static void
+__tracepoint_callsite__destroy(void)
+{
+ int ret;
+
+ if (--__tracepoint_callsite_registered)
+ return;
+ if (tracepoint_callsite_dlopen.tracepoint_unregister_lib_callsite)
+ tracepoint_callsite_dlopen.tracepoint_unregister_lib_callsite(__start___tracepoint_callsite_ptrs,
+ __stop___tracepoint_callsite_ptrs -
+ __start___tracepoint_callsite_ptrs);
+ if (tracepoint_callsite_dlopen.liblttngust_handle) {
+ ret = dlclose(tracepoint_callsite_dlopen.liblttngust_handle);
+ assert(!ret);
+ memset(&tracepoint_callsite_dlopen, 0, sizeof(tracepoint_callsite_dlopen));
+ }
+}
+
#ifdef TRACEPOINT_DEFINE
/*
struct tracepoint_dlopen tracepoint_dlopen
__attribute__((weak, visibility("hidden")));
-static void __attribute__((constructor)) __tracepoints__init(void)
+static void lttng_ust_notrace __attribute__((constructor))
+__tracepoints__init(void);
+static void
+__tracepoints__init(void)
{
if (__tracepoint_registered++)
return;
__start___tracepoints_ptrs);
}
-static void __attribute__((destructor)) __tracepoints__destroy(void)
+static void lttng_ust_notrace __attribute__((destructor))
+__tracepoints__destroy(void);
+static void
+__tracepoints__destroy(void)
{
int ret;
#define TRACEPOINT_LOGLEVEL(provider, name, loglevel)
#endif /* #ifndef TRACEPOINT_LOGLEVEL */
+
+#ifndef TRACEPOINT_MODEL_EMF_URI
+
+#define TRACEPOINT_MODEL_EMF_URI(provider, name, uri)
+
+#endif /* #ifndef TRACEPOINT_MODEL_EMF_URI */