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 <linux/slab.h>
13 #include <linux/compat.h>
14 #include <asm/ptrace.h>
15 #include <asm/syscall.h>
17 #include "ltt-events.h"
20 static inline int is_compat_task(void)
26 static void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
);
29 * Take care of NOARGS not supported by mainline.
31 #define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
32 #define DEFINE_EVENT_NOARGS(template, name)
33 #define TRACE_EVENT_NOARGS(name, struct, assign, print)
36 * Create LTTng tracepoint probes.
38 #define LTTNG_PACKAGE_BUILD
39 #define CREATE_TRACE_POINTS
40 #define TP_MODULE_OVERRIDE
41 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
43 /* Hijack probe callback for system calls */
44 #define TP_PROBE_CB(_template) &syscall_entry_probe
45 #include "instrumentation/syscalls/headers/syscalls_integers.h"
46 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
49 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
51 #undef TP_MODULE_OVERRIDE
52 #undef LTTNG_PACKAGE_BUILD
53 #undef CREATE_TRACE_POINTS
55 struct trace_syscall_entry
{
57 const struct lttng_event_desc
*desc
;
58 const struct lttng_event_field
*fields
;
62 #undef TRACE_SYSCALL_TABLE
63 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
65 .func = __event_probe__##_template, \
66 .nrargs = (_nrargs), \
67 .fields = __event_fields___##_template, \
68 .desc = &__event_desc___##_name, \
71 #define CREATE_SYSCALL_TABLE
73 static const struct trace_syscall_entry sc_table
[] = {
74 #include "instrumentation/syscalls/headers/syscalls_integers.h"
75 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
78 /* Create compatibility syscall table */
79 static const struct trace_syscall_entry compat_sc_table
[] = {
80 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
81 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
84 #undef CREATE_SYSCALL_TABLE
86 static void syscall_entry_unknown(struct ltt_event
*event
,
87 struct pt_regs
*regs
, unsigned int id
)
89 unsigned long args
[UNKNOWN_SYSCALL_NRARGS
];
91 syscall_get_arguments(current
, regs
, 0, UNKNOWN_SYSCALL_NRARGS
, args
);
92 __event_probe__sys_unknown(event
, id
, args
);
96 * Currently, given that the kernel syscall metadata extraction only
97 * considers native system calls (not 32-bit compability ones), we
98 * fall-back on the "unknown" system call tracing for 32-bit compat.
100 static void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
)
102 struct ltt_channel
*chan
= __data
;
103 struct ltt_event
*event
, *unknown_event
;
104 const struct trace_syscall_entry
*table
, *entry
;
107 if (unlikely(is_compat_task())) {
108 table
= compat_sc_table
;
109 table_len
= ARRAY_SIZE(compat_sc_table
);
110 unknown_event
= chan
->sc_compat_unknown
;
113 table_len
= ARRAY_SIZE(sc_table
);
114 unknown_event
= chan
->sc_unknown
;
116 if (unlikely(id
>= table_len
)) {
117 syscall_entry_unknown(unknown_event
, regs
, id
);
120 if (unlikely(is_compat_task()))
121 event
= chan
->compat_sc_table
[id
];
123 event
= chan
->sc_table
[id
];
124 if (unlikely(!event
)) {
125 syscall_entry_unknown(unknown_event
, regs
, id
);
129 WARN_ON_ONCE(!entry
);
131 switch (entry
->nrargs
) {
134 void (*fptr
)(void *__data
) = entry
->func
;
141 void (*fptr
)(void *__data
, unsigned long arg0
) = entry
->func
;
142 unsigned long args
[1];
144 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
145 fptr(event
, args
[0]);
150 void (*fptr
)(void *__data
,
152 unsigned long arg1
) = entry
->func
;
153 unsigned long args
[2];
155 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
156 fptr(event
, args
[0], args
[1]);
161 void (*fptr
)(void *__data
,
164 unsigned long arg2
) = entry
->func
;
165 unsigned long args
[3];
167 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
168 fptr(event
, args
[0], args
[1], args
[2]);
173 void (*fptr
)(void *__data
,
177 unsigned long arg3
) = entry
->func
;
178 unsigned long args
[4];
180 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
181 fptr(event
, args
[0], args
[1], args
[2], args
[3]);
186 void (*fptr
)(void *__data
,
191 unsigned long arg4
) = entry
->func
;
192 unsigned long args
[5];
194 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
195 fptr(event
, args
[0], args
[1], args
[2], args
[3], args
[4]);
200 void (*fptr
)(void *__data
,
206 unsigned long arg5
) = entry
->func
;
207 unsigned long args
[6];
209 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
210 fptr(event
, args
[0], args
[1], args
[2],
211 args
[3], args
[4], args
[5]);
220 int fill_table(const struct trace_syscall_entry
*table
, size_t table_len
,
221 struct ltt_event
**chan_table
, struct ltt_channel
*chan
, void *filter
)
225 /* Allocate events for each syscall, insert into table */
226 for (i
= 0; i
< table_len
; i
++) {
227 struct lttng_kernel_event ev
;
228 const struct lttng_event_desc
*desc
= table
[i
].desc
;
231 /* Unknown syscall */
235 * Skip those already populated by previous failed
236 * register for this channel.
240 memset(&ev
, 0, sizeof(ev
));
241 strncpy(ev
.name
, desc
->name
, LTTNG_SYM_NAME_LEN
);
242 ev
.name
[LTTNG_SYM_NAME_LEN
- 1] = '\0';
243 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
244 chan_table
[i
] = ltt_event_create(chan
, &ev
, filter
,
246 if (!chan_table
[i
]) {
248 * If something goes wrong in event registration
249 * after the first one, we have no choice but to
250 * leave the previous events in there, until
251 * deleted by session teardown.
259 int lttng_syscalls_register(struct ltt_channel
*chan
, void *filter
)
263 wrapper_vmalloc_sync_all();
265 if (!chan
->sc_table
) {
266 /* create syscall table mapping syscall to events */
267 chan
->sc_table
= kzalloc(sizeof(struct ltt_event
*)
268 * ARRAY_SIZE(sc_table
), GFP_KERNEL
);
274 if (!chan
->compat_sc_table
) {
275 /* create syscall table mapping compat syscall to events */
276 chan
->compat_sc_table
= kzalloc(sizeof(struct ltt_event
*)
277 * ARRAY_SIZE(compat_sc_table
), GFP_KERNEL
);
278 if (!chan
->compat_sc_table
)
282 if (!chan
->sc_unknown
) {
283 struct lttng_kernel_event ev
;
284 const struct lttng_event_desc
*desc
=
285 &__event_desc___sys_unknown
;
287 memset(&ev
, 0, sizeof(ev
));
288 strncpy(ev
.name
, desc
->name
, LTTNG_SYM_NAME_LEN
);
289 ev
.name
[LTTNG_SYM_NAME_LEN
- 1] = '\0';
290 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
291 chan
->sc_unknown
= ltt_event_create(chan
, &ev
, filter
,
293 if (!chan
->sc_unknown
) {
298 if (!chan
->sc_compat_unknown
) {
299 struct lttng_kernel_event ev
;
300 const struct lttng_event_desc
*desc
=
301 &__event_desc___compat_sys_unknown
;
303 memset(&ev
, 0, sizeof(ev
));
304 strncpy(ev
.name
, desc
->name
, LTTNG_SYM_NAME_LEN
);
305 ev
.name
[LTTNG_SYM_NAME_LEN
- 1] = '\0';
306 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
307 chan
->sc_compat_unknown
= ltt_event_create(chan
, &ev
, filter
,
309 if (!chan
->sc_compat_unknown
) {
314 if (!chan
->sc_exit
) {
315 struct lttng_kernel_event ev
;
316 const struct lttng_event_desc
*desc
=
317 &__event_desc___exit_syscall
;
319 memset(&ev
, 0, sizeof(ev
));
320 strncpy(ev
.name
, desc
->name
, LTTNG_SYM_NAME_LEN
);
321 ev
.name
[LTTNG_SYM_NAME_LEN
- 1] = '\0';
322 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
323 chan
->sc_exit
= ltt_event_create(chan
, &ev
, filter
,
325 if (!chan
->sc_exit
) {
330 ret
= fill_table(sc_table
, ARRAY_SIZE(sc_table
),
331 chan
->sc_table
, chan
, filter
);
335 ret
= fill_table(compat_sc_table
, ARRAY_SIZE(compat_sc_table
),
336 chan
->compat_sc_table
, chan
, filter
);
340 ret
= tracepoint_probe_register("sys_enter",
341 (void *) syscall_entry_probe
, chan
);
345 * We change the name of sys_exit tracepoint due to namespace
346 * conflict with sys_exit syscall entry.
348 ret
= tracepoint_probe_register("sys_exit",
349 (void *) __event_probe__exit_syscall
,
352 WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
353 (void *) syscall_entry_probe
, chan
));
359 * Only called at session destruction.
361 int lttng_syscalls_unregister(struct ltt_channel
*chan
)
367 ret
= tracepoint_probe_unregister("sys_exit",
368 (void *) __event_probe__exit_syscall
,
372 ret
= tracepoint_probe_unregister("sys_enter",
373 (void *) syscall_entry_probe
, chan
);
376 /* ltt_event destroy will be performed by ltt_session_destroy() */
377 kfree(chan
->sc_table
);
379 kfree(chan
->compat_sc_table
);