From a053707937a4ea4df643641cdfa2959454e9e75c Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Wed, 18 May 2016 16:51:20 +0100 Subject: [PATCH] dtrace: use perf_events probes For every trace point defined, also define an SDT probe. This allows DTrace to expose probe points maintained by upstream. [nca: fixed TODOs: added DTRACE_UINTPTR_CAST_EACH so that tracepoints that pass structures by value will still compile: we jam the structure into a uintptr if it will fit, otherwise passing its address in. This is only partial, so far: there is no CTF type info for any of these new probes, but this is a relatively minor issue that can be fixed later.] Orabug: 23004534 Signed-off-by: Timothy J Fontaine Signed-off-by: Nick Alcock Acked-by: Kris Van Hees --- include/linux/sdt.h | 63 ++++++++++++++++++++++++++++++++++++++ include/linux/tracepoint.h | 6 +++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/include/linux/sdt.h b/include/linux/sdt.h index a1f12e7a0c9d..c44db3de6654 100644 --- a/include/linux/sdt.h +++ b/include/linux/sdt.h @@ -122,6 +122,68 @@ extern "C" { (uintptr_t)(arg6), (uintptr_t)(arg7), (uintptr_t)(arg8)); \ } +/* This counts the number of args */ +#define DTRACE_NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,N,...) N +#define DTRACE_NARGS(...) DTRACE_NARGS_SEQ(__VA_ARGS__, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + +/* This will let macros expand before concating them */ +#define DTRACE_PRIMITIVE_CAT(x, y) x ## y +#define DTRACE_CAT(x, y) DTRACE_PRIMITIVE_CAT(x, y) + +/* This will call a macro on each argument passed in */ +#define DTRACE_APPLY(macro, ...) DTRACE_CAT(DTRACE_APPLY_, DTRACE_NARGS(__VA_ARGS__))(macro, __VA_ARGS__) +#define DTRACE_APPLY_1(m, x1) m(x1) +#define DTRACE_APPLY_2(m, x1, x2) m(x1), m(x2) +#define DTRACE_APPLY_3(m, x1, x2, x3) m(x1), m(x2), m(x3) +#define DTRACE_APPLY_4(m, x1, x2, x3, x4) m(x1), m(x2), m(x3), m(x4) +#define DTRACE_APPLY_5(m, x1, x2, x3, x4, x5) m(x1), m(x2), m(x3), m(x4), m(x5) +#define DTRACE_APPLY_6(m, x1, x2, x3, x4, x5, x6) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6) +#define DTRACE_APPLY_7(m, x1, x2, x3, x4, x5, x6, x7) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7) +#define DTRACE_APPLY_8(m, x1, x2, x3, x4, x5, x6, x7, x8) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) + +/* + * Without investigation I went ahead and assumed the most arguments that could + * be passed would be 8, but this is purely arbitrary. However, inexplicably + * there are existing tracepoints that pass as many as 18 arguments! + */ + +#define DTRACE_APPLY_9(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_10(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_11(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_12(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_13(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_14(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_15(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_16(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_17(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) +#define DTRACE_APPLY_18(m, x1, x2, x3, x4, x5, x6, x7, x8, ...) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) + +/* + * Convert everything to the appropriate integral type, unless too large to fit + * into any of them, in which case its address is taken instead. + */ + +#define DTRACE_UINTPTR_CAST_EACH(x) ({ \ + union { \ + typeof((x)) __val; \ + unsigned char __c; \ + unsigned short __s; \ + unsigned int __i; \ + unsigned long __l; \ + unsigned long long __ll; } __u = { .__val = (x) }; \ + __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__c), __u.__c, \ + __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__s), __u.__s, \ + __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__i), __u.__i, \ + __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__l), __u.__l, \ + __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__ll), __u.__ll,\ + (uintptr_t)&(__u.__val))))));}) +#define DTRACE_UINTPTR_EACH(x) uintptr_t + +#define DTRACE_PROBE_TRACEPOINT(name, args...) { \ + extern void __dtrace_probe_##name(DTRACE_APPLY(DTRACE_UINTPTR_EACH, args)); \ + __dtrace_probe_##name(DTRACE_APPLY(DTRACE_UINTPTR_CAST_EACH, args)); \ +} + typedef struct sdt_probedesc { char *sdpd_name; /* probe name */ char *sdpd_func; /* probe function */ @@ -150,6 +212,7 @@ typedef struct sdt_probedesc { #define DTRACE_PROBE8(name, type1, arg1, type2, arg2, type3, arg3, \ type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8) \ DTRACE_PROBE(name) +#define DTRACE_PROBE_TRACEPOINT(name, args...) #endif /* CONFIG_DTRACE */ diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index a5f7f3ecafa3..c913baf53e36 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -18,6 +18,7 @@ #include #include #include +#include struct module; struct tracepoint; @@ -176,6 +177,7 @@ extern void syscall_unregfunc(void); extern struct tracepoint __tracepoint_##name; \ static inline void trace_##name(proto) \ { \ + DTRACE_PROBE_TRACEPOINT(name, args); \ if (static_key_false(&__tracepoint_##name.key)) \ __DO_TRACE(&__tracepoint_##name, \ TP_PROTO(data_proto), \ @@ -237,7 +239,9 @@ extern void syscall_unregfunc(void); #else /* !CONFIG_TRACEPOINTS */ #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ static inline void trace_##name(proto) \ - { } \ + { \ + DTRACE_PROBE_TRACEPOINT(name, args); \ + } \ static inline void trace_##name##_rcuidle(proto) \ { } \ static inline int \ -- 2.50.1