From 243433293dc4bda8e67df4eadc9d74f4238ab7a3 Mon Sep 17 00:00:00 2001 From: Nick Alcock Date: Wed, 14 Sep 2016 02:10:06 +0100 Subject: [PATCH] dtrace: record SDT and perf probe types in a new ELF section Before now, the types specified in the SDT probe macros in include/linux/sdt.h were simply thrown away: DTrace was never informed of them, and instead got type information for SDT probes from a hardwired list in the out-of-tree sdt module. As a start to fixing this, export the SDT type information into a new ELF section named _dtrace_sdt_args. Both native SDT probes and perf probes translated into SDT probes use the same section: its format is a sequence of probe type strings, with individual arguments separated by commas, each type string separated from the next by a NUL: type string, comma-separated\0 ... (This is the same format used by perf probe prototype declarations, and is what you'd get if you removed the argument names from a DTrace SDT probe specification.) The only difference between SDT and perf probe type strings is that the type string for perf probes is also used to define a tracing function, so it includes argument names. The SDT format has various other extensions which do not affect this commit so will be described later. The type strings in the section are in no particular order (it depends on the order in the source code) and may contain duplicates, so to associate each string with a probe, there is another section, _dtrace_sdt_names, which is a simple null-terminated array (string table) of names, associated 1:1 with the type strings in the _dtrace_sdt_types section. At this point in the patch series, nothing uses the newly-added sections. Signed-off-by: Nick Alcock Acked-by: Kris Van Hees Orabug: 24661801 --- include/asm-generic/vmlinux.lds.h | 16 ++++ include/linux/sdt.h | 120 +++++++++++++++++++++++++++++- include/linux/tracepoint.h | 2 + 3 files changed, 135 insertions(+), 3 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8bd374d3cf21..1839145b44a2 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -120,6 +120,20 @@ #define KPROBE_BLACKLIST() #endif +#ifdef CONFIG_DTRACE +#define DTRACE_SDT_NAMES() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_dtrace_sdt_names) = .; \ + *(_dtrace_sdt_names) \ + VMLINUX_SYMBOL(__stop_dtrace_sdt_names) = .; +#define DTRACE_SDT_ARGS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_dtrace_sdt_args) = .; \ + *(_dtrace_sdt_args) \ + VMLINUX_SYMBOL(__stop_dtrace_sdt_args) = .; +#else +#define DTRACE_SDT_NAMES() +#define DTRACE_SDT_ARGS() +#endif + #ifdef CONFIG_EVENT_TRACING #define FTRACE_EVENTS() . = ALIGN(8); \ VMLINUX_SYMBOL(__start_ftrace_events) = .; \ @@ -507,6 +521,8 @@ FTRACE_EVENTS() \ TRACE_SYSCALLS() \ KPROBE_BLACKLIST() \ + DTRACE_SDT_NAMES() \ + DTRACE_SDT_ARGS() \ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ diff --git a/include/linux/sdt.h b/include/linux/sdt.h index d659caf2f996..42ae116b21c6 100644 --- a/include/linux/sdt.h +++ b/include/linux/sdt.h @@ -57,6 +57,11 @@ extern "C" { #else /* __KERNEL__ */ +#include + +#define PROBENAME_STR(str) ".ascii \"" __stringify(str) "\"\n" +#define ARG_STR(str) ".ascii \"" __stringify(str) ",\"\n" + #define DTRACE_PROBE(name) { \ extern void __dtrace_probe_##name(void); \ __dtrace_probe_##name(); \ @@ -65,17 +70,44 @@ extern "C" { #define DTRACE_PROBE1(name, type1, arg1) { \ extern void __dtrace_probe_##name(uintptr_t); \ __dtrace_probe_##name((uintptr_t)(arg1)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ".byte 0\n" \ + ".popsection\n"); \ } #define DTRACE_PROBE2(name, type1, arg1, type2, arg2) { \ extern void __dtrace_probe_##name(uintptr_t, uintptr_t); \ __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ARG_STR(type2) \ + ".byte 0\n" \ + ".popsection\n"); \ } #define DTRACE_PROBE3(name, type1, arg1, type2, arg2, type3, arg3) { \ extern void __dtrace_probe_##name(uintptr_t, uintptr_t, uintptr_t); \ __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \ (uintptr_t)(arg3)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ARG_STR(type2) \ + ARG_STR(type3) \ + ".byte 0\n" \ + ".popsection\n"); \ } #define DTRACE_PROBE4(name, type1, arg1, type2, arg2, \ @@ -84,6 +116,17 @@ extern "C" { uintptr_t, uintptr_t); \ __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \ (uintptr_t)(arg3), (uintptr_t)(arg4)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ARG_STR(type2) \ + ARG_STR(type3) \ + ARG_STR(type4) \ + ".byte 0\n" \ + ".popsection\n"); \ } #define DTRACE_PROBE5(name, type1, arg1, type2, arg2, \ @@ -92,6 +135,18 @@ extern "C" { uintptr_t, uintptr_t, uintptr_t); \ __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \ (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ARG_STR(type2) \ + ARG_STR(type3) \ + ARG_STR(type4) \ + ARG_STR(type5) \ + ".byte 0\n" \ + ".popsection\n"); \ } #define DTRACE_PROBE6(name, type1, arg1, type2, arg2, \ @@ -101,6 +156,19 @@ extern "C" { __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \ (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5), \ (uintptr_t)(arg6)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ARG_STR(type2) \ + ARG_STR(type3) \ + ARG_STR(type4) \ + ARG_STR(type5) \ + ARG_STR(type6) \ + ".byte 0\n" \ + ".popsection\n"); \ } #define DTRACE_PROBE7(name, type1, arg1, type2, arg2, type3, arg3, \ @@ -110,6 +178,20 @@ extern "C" { __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \ (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5), \ (uintptr_t)(arg6), (uintptr_t)(arg7)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ARG_STR(type2) \ + ARG_STR(type3) \ + ARG_STR(type4) \ + ARG_STR(type5) \ + ARG_STR(type6) \ + ARG_STR(type7) \ + ".byte 0\n" \ + ".popsection\n"); \ } #define DTRACE_PROBE8(name, type1, arg1, type2, arg2, type3, arg3, \ @@ -120,19 +202,40 @@ extern "C" { __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \ (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5), \ (uintptr_t)(arg6), (uintptr_t)(arg7), (uintptr_t)(arg8)); \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + PROBENAME_STR(name) \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ARG_STR(type1) \ + ARG_STR(type2) \ + ARG_STR(type3) \ + ARG_STR(type4) \ + ARG_STR(type5) \ + ARG_STR(type6) \ + ARG_STR(type7) \ + ARG_STR(type8) \ + ".byte 0\n" \ + ".popsection\n"); \ } #ifdef CONFIG_DT_SDT_PERF -/* This counts the number of args */ +/* + * 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 */ +/* + * This will let macros expand before concatting 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 */ +/* + * 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) @@ -186,9 +289,19 @@ extern "C" { __dtrace_probe___perf_##name(DTRACE_APPLY(DTRACE_UINTPTR_CAST_EACH, args)); \ } +#define DTRACE_PROTO_TRACEPOINT(name, proto...) { \ + asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ + ".ascii \"" __stringify(__perf_##name) "\"\n" \ + ".byte 0\n" \ + ".popsection\n" \ + ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ + ".asciz \"" __stringify(proto) "\"\n" \ + ".popsection\n"); \ +} #else #define DTRACE_PROBE_TRACEPOINT(name, args...) +#define DTRACE_PROTO_TRACEPOINT(name, proto...) #endif @@ -221,6 +334,7 @@ typedef struct sdt_probedesc { type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8) \ DTRACE_PROBE(name) #define DTRACE_PROBE_TRACEPOINT(name, args...) +#define DTRACE_PROTO_TRACEPOINT(name, proto) #endif /* CONFIG_DTRACE */ diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index c913baf53e36..4ab84ae8e3fd 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -178,6 +178,7 @@ extern void syscall_unregfunc(void); static inline void trace_##name(proto) \ { \ DTRACE_PROBE_TRACEPOINT(name, args); \ + DTRACE_PROTO_TRACEPOINT(name, proto); \ if (static_key_false(&__tracepoint_##name.key)) \ __DO_TRACE(&__tracepoint_##name, \ TP_PROTO(data_proto), \ @@ -241,6 +242,7 @@ extern void syscall_unregfunc(void); static inline void trace_##name(proto) \ { \ DTRACE_PROBE_TRACEPOINT(name, args); \ + DTRACE_PROTO_TRACEPOINT(name, proto); \ } \ static inline void trace_##name##_rcuidle(proto) \ { } \ -- 2.50.1