2 * probes/lttng-probe-sched.c
4 * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * Dual LGPL v2.1/GPL v2 license.
11 #include <linux/module.h>
12 #include "../ltt-events.h"
14 #ifndef SYSCALL_DETAIL
17 * Create the tracepoint static inlines from the kernel to validate that our
18 * trace event macros match the kernel we run on.
20 #include <trace/events/syscalls.h>
23 * Create LTTng tracepoint probes.
25 #define LTTNG_PACKAGE_BUILD
26 #define CREATE_TRACE_POINTS
27 #define TRACE_INCLUDE_PATH ../instrumentation/events/lttng-module
29 #include "../instrumentation/events/lttng-module/syscalls.h"
31 #else /* SYSCALL_DETAIL */
33 #include <linux/slab.h>
34 #include <asm/ptrace.h>
35 #include <asm/syscall.h>
37 static void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
);
38 static int lttng_syscalls_register_probe(struct lttng_probe_desc
*desc
);
39 static void lttng_syscalls_unregister_probe(struct lttng_probe_desc
*desc
);
41 static struct lttng_probe_desc
*syscall_probe_desc
;
44 * Create LTTng tracepoint probes.
46 #define LTTNG_PACKAGE_BUILD
47 #define CREATE_TRACE_POINTS
49 /* Hijack probe callback for system calls */
50 #define TP_PROBE_CB(_template) &syscall_entry_probe
51 #define TP_REGISTER_OVERRIDE lttng_syscalls_register_probe
52 #define TP_UNREGISTER_OVERRIDE lttng_syscalls_unregister_probe
54 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
56 #include "../instrumentation/syscalls/headers/syscalls.h"
58 #undef TP_UNREGISTER_OVERRIDE
59 #undef TP_REGISTER_OVERRIDE
61 #undef LTTNG_PACKAGE_BUILD
62 #undef CREATE_TRACE_POINTS
64 struct trace_syscall_entry
{
66 const struct lttng_event_desc
*desc
; /* Set dynamically */
67 const struct lttng_event_field
*fields
;
71 static int sc_table_desc_filled
;
73 #define CREATE_SYSCALL_TABLE
75 #undef TRACE_SYSCALL_TABLE
76 #define TRACE_SYSCALL_TABLE(_name, _nr, _nrargs) \
78 .func = __event_probe__##_name, \
79 .nrargs = (_nrargs), \
80 .fields = __event_fields___##_name, \
83 static struct trace_syscall_entry sc_table
[] = {
84 #include "../instrumentation/syscalls/headers/syscalls.h"
87 #undef CREATE_SYSCALL_TABLE
89 static void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
)
91 struct trace_syscall_entry
*entry
;
92 struct ltt_channel
*chan
= __data
;
93 struct ltt_event
*event
;
95 if (unlikely(id
>= ARRAY_SIZE(sc_table
)))
97 entry
= &sc_table
[id
];
98 if (unlikely(!entry
->func
))
100 event
= chan
->sc_table
[id
];
101 WARN_ON_ONCE(!event
);
103 switch (entry
->nrargs
) {
106 void (*fptr
)(void *__data
) = entry
->func
;
113 void (*fptr
)(void *__data
, unsigned long arg0
) = entry
->func
;
114 unsigned long args
[1];
116 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
117 fptr(event
, args
[0]);
122 void (*fptr
)(void *__data
,
124 unsigned long arg1
) = entry
->func
;
125 unsigned long args
[2];
127 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
128 fptr(event
, args
[0], args
[1]);
133 void (*fptr
)(void *__data
,
136 unsigned long arg2
) = entry
->func
;
137 unsigned long args
[3];
139 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
140 fptr(event
, args
[0], args
[1], args
[2]);
145 void (*fptr
)(void *__data
,
149 unsigned long arg3
) = entry
->func
;
150 unsigned long args
[4];
152 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
153 fptr(event
, args
[0], args
[1], args
[2], args
[3]);
158 void (*fptr
)(void *__data
,
163 unsigned long arg4
) = entry
->func
;
164 unsigned long args
[5];
166 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
167 fptr(event
, args
[0], args
[1], args
[2], args
[3], args
[4]);
172 void (*fptr
)(void *__data
,
178 unsigned long arg5
) = entry
->func
;
179 unsigned long args
[6];
181 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
182 fptr(event
, args
[0], args
[1], args
[2],
183 args
[3], args
[4], args
[5]);
191 static const struct lttng_event_desc
*find_syscall_desc(unsigned int id
)
195 for (i
= 0; i
< syscall_probe_desc
->nr_events
; i
++) {
196 if (syscall_probe_desc
->event_desc
[i
].fields
197 == sc_table
[id
].fields
)
198 return &syscall_probe_desc
->event_desc
[i
];
204 static void fill_sc_table_desc(void)
208 if (sc_table_desc_filled
)
211 * This is O(n^2), but rare. Eventually get the TRACE_EVENT code
212 * to emit per-event symbols to skip this.
214 for (i
= 0; i
< ARRAY_SIZE(sc_table
); i
++) {
215 const struct lttng_event_desc
**desc
= &sc_table
[i
].desc
;
217 if (!sc_table
[i
].func
)
219 (*desc
) = find_syscall_desc(i
);
221 sc_table_desc_filled
= 1;
225 int lttng_syscalls_register(struct ltt_channel
*chan
, void *filter
)
230 fill_sc_table_desc();
232 if (!chan
->sc_table
) {
233 /* create syscall table mapping syscall to events */
234 chan
->sc_table
= kzalloc(sizeof(struct ltt_event
*)
235 * ARRAY_SIZE(sc_table
), GFP_KERNEL
);
240 /* Allocate events for each syscall, insert into table */
241 for (i
= 0; i
< ARRAY_SIZE(sc_table
); i
++) {
242 struct lttng_kernel_event ev
;
243 const struct lttng_event_desc
*desc
= sc_table
[i
].desc
;
246 * Skip those already populated by previous failed
247 * register for this channel.
249 if (chan
->sc_table
[i
])
251 memset(&ev
, 0, sizeof(ev
));
252 strncpy(ev
.name
, desc
->name
, LTTNG_SYM_NAME_LEN
);
253 ev
.name
[LTTNG_SYM_NAME_LEN
- 1] = '\0';
254 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
255 chan
->sc_table
[i
] = ltt_event_create(chan
, &ev
, filter
);
256 if (!chan
->sc_table
[i
]) {
258 * If something goes wrong in event registration
259 * after the first one, we have no choice but to
260 * leave the previous events in there, until
261 * deleted by session teardown.
266 ret
= tracepoint_probe_register("syscall_entry",
267 (void *) syscall_entry_probe
, chan
);
272 * Only called at session destruction.
274 int lttng_syscalls_unregister(struct ltt_channel
*chan
)
280 ret
= tracepoint_probe_unregister("syscall_entry",
281 (void *) syscall_entry_probe
, chan
);
284 /* ltt_event destroy will be performed by ltt_session_destroy() */
285 kfree(chan
->sc_table
);
289 static int lttng_syscalls_register_probe(struct lttng_probe_desc
*desc
)
291 WARN_ON_ONCE(syscall_probe_desc
);
292 syscall_probe_desc
= desc
;
296 static void lttng_syscalls_unregister_probe(struct lttng_probe_desc
*desc
)
298 WARN_ON_ONCE(!syscall_probe_desc
);
299 syscall_probe_desc
= NULL
;
302 #endif /* SYSCALL_DETAIL */
304 MODULE_LICENSE("GPL and additional rights");
305 MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
306 MODULE_DESCRIPTION("LTTng sched probes");