4 * LTTng syscall probes.
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/compat.h>
26 #include <asm/ptrace.h>
27 #include <asm/syscall.h>
29 #include "lttng-events.h"
32 static inline int is_compat_task(void)
39 void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
);
42 * Take care of NOARGS not supported by mainline.
44 #define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
45 #define DEFINE_EVENT_NOARGS(template, name)
46 #define TRACE_EVENT_NOARGS(name, struct, assign, print)
49 * Create LTTng tracepoint probes.
51 #define LTTNG_PACKAGE_BUILD
52 #define CREATE_TRACE_POINTS
53 #define TP_MODULE_OVERRIDE
54 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
56 #define PARAMS(args...) args
58 /* Hijack probe callback for system calls */
60 #define TP_PROBE_CB(_template) &syscall_entry_probe
61 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
62 TRACE_EVENT(_name, PARAMS(_proto), PARAMS(_args),\
63 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
64 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
65 DECLARE_EVENT_CLASS_NOARGS(_name, PARAMS(_struct), PARAMS(_assign),\
67 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
68 DEFINE_EVENT_NOARGS(_template, _name)
70 #define TRACE_SYSTEM syscalls_integers
71 #include "instrumentation/syscalls/headers/syscalls_integers.h"
73 #define TRACE_SYSTEM syscalls_pointers
74 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
77 #undef SC_DECLARE_EVENT_CLASS_NOARGS
78 #undef SC_DEFINE_EVENT_NOARGS
80 #define TRACE_SYSTEM syscalls_unknown
81 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
84 /* For compat syscalls */
85 #undef _TRACE_SYSCALLS_integers_H
86 #undef _TRACE_SYSCALLS_pointers_H
88 /* Hijack probe callback for system calls */
90 #define TP_PROBE_CB(_template) &syscall_entry_probe
91 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
92 TRACE_EVENT(compat_##_name, PARAMS(_proto), PARAMS(_args), \
93 PARAMS(_struct), PARAMS(_assign), \
95 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
96 DECLARE_EVENT_CLASS_NOARGS(compat_##_name, PARAMS(_struct), \
97 PARAMS(_assign), PARAMS(_printk))
98 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
99 DEFINE_EVENT_NOARGS(compat_##_template, compat_##_name)
100 #define TRACE_SYSTEM compat_syscalls_integers
101 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
103 #define TRACE_SYSTEM compat_syscalls_pointers
104 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
106 #undef SC_TRACE_EVENT
107 #undef SC_DECLARE_EVENT_CLASS_NOARGS
108 #undef SC_DEFINE_EVENT_NOARGS
111 #undef TP_MODULE_OVERRIDE
112 #undef LTTNG_PACKAGE_BUILD
113 #undef CREATE_TRACE_POINTS
115 struct trace_syscall_entry
{
117 const struct lttng_event_desc
*desc
;
118 const struct lttng_event_field
*fields
;
122 #define CREATE_SYSCALL_TABLE
124 #undef TRACE_SYSCALL_TABLE
125 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
127 .func = __event_probe__##_template, \
128 .nrargs = (_nrargs), \
129 .fields = __event_fields___##_template, \
130 .desc = &__event_desc___##_name, \
133 static const struct trace_syscall_entry sc_table
[] = {
134 #include "instrumentation/syscalls/headers/syscalls_integers.h"
135 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
138 #undef TRACE_SYSCALL_TABLE
139 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
141 .func = __event_probe__##compat_##_template, \
142 .nrargs = (_nrargs), \
143 .fields = __event_fields___##compat_##_template,\
144 .desc = &__event_desc___##compat_##_name, \
147 /* Create compatibility syscall table */
148 const struct trace_syscall_entry compat_sc_table
[] = {
149 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
150 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
153 #undef CREATE_SYSCALL_TABLE
155 static void syscall_entry_unknown(struct lttng_event
*event
,
156 struct pt_regs
*regs
, unsigned int id
)
158 unsigned long args
[UNKNOWN_SYSCALL_NRARGS
];
160 syscall_get_arguments(current
, regs
, 0, UNKNOWN_SYSCALL_NRARGS
, args
);
161 if (unlikely(is_compat_task()))
162 __event_probe__compat_sys_unknown(event
, id
, args
);
164 __event_probe__sys_unknown(event
, id
, args
);
167 void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
)
169 struct lttng_channel
*chan
= __data
;
170 struct lttng_event
*event
, *unknown_event
;
171 const struct trace_syscall_entry
*table
, *entry
;
174 if (unlikely(is_compat_task())) {
175 table
= compat_sc_table
;
176 table_len
= ARRAY_SIZE(compat_sc_table
);
177 unknown_event
= chan
->sc_compat_unknown
;
180 table_len
= ARRAY_SIZE(sc_table
);
181 unknown_event
= chan
->sc_unknown
;
183 if (unlikely(id
>= table_len
)) {
184 syscall_entry_unknown(unknown_event
, regs
, id
);
187 if (unlikely(is_compat_task()))
188 event
= chan
->compat_sc_table
[id
];
190 event
= chan
->sc_table
[id
];
191 if (unlikely(!event
)) {
192 syscall_entry_unknown(unknown_event
, regs
, id
);
196 WARN_ON_ONCE(!entry
);
198 switch (entry
->nrargs
) {
201 void (*fptr
)(void *__data
) = entry
->func
;
208 void (*fptr
)(void *__data
, unsigned long arg0
) = entry
->func
;
209 unsigned long args
[1];
211 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
212 fptr(event
, args
[0]);
217 void (*fptr
)(void *__data
,
219 unsigned long arg1
) = entry
->func
;
220 unsigned long args
[2];
222 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
223 fptr(event
, args
[0], args
[1]);
228 void (*fptr
)(void *__data
,
231 unsigned long arg2
) = entry
->func
;
232 unsigned long args
[3];
234 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
235 fptr(event
, args
[0], args
[1], args
[2]);
240 void (*fptr
)(void *__data
,
244 unsigned long arg3
) = entry
->func
;
245 unsigned long args
[4];
247 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
248 fptr(event
, args
[0], args
[1], args
[2], args
[3]);
253 void (*fptr
)(void *__data
,
258 unsigned long arg4
) = entry
->func
;
259 unsigned long args
[5];
261 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
262 fptr(event
, args
[0], args
[1], args
[2], args
[3], args
[4]);
267 void (*fptr
)(void *__data
,
273 unsigned long arg5
) = entry
->func
;
274 unsigned long args
[6];
276 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
277 fptr(event
, args
[0], args
[1], args
[2],
278 args
[3], args
[4], args
[5]);
286 /* noinline to diminish caller stack size */
288 int fill_table(const struct trace_syscall_entry
*table
, size_t table_len
,
289 struct lttng_event
**chan_table
, struct lttng_channel
*chan
, void *filter
)
291 const struct lttng_event_desc
*desc
;
294 /* Allocate events for each syscall, insert into table */
295 for (i
= 0; i
< table_len
; i
++) {
296 struct lttng_kernel_event ev
;
297 desc
= table
[i
].desc
;
300 /* Unknown syscall */
304 * Skip those already populated by previous failed
305 * register for this channel.
309 memset(&ev
, 0, sizeof(ev
));
310 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
311 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
312 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
313 chan_table
[i
] = lttng_event_create(chan
, &ev
, filter
,
315 if (!chan_table
[i
]) {
317 * If something goes wrong in event registration
318 * after the first one, we have no choice but to
319 * leave the previous events in there, until
320 * deleted by session teardown.
328 int lttng_syscalls_register(struct lttng_channel
*chan
, void *filter
)
330 struct lttng_kernel_event ev
;
333 wrapper_vmalloc_sync_all();
335 if (!chan
->sc_table
) {
336 /* create syscall table mapping syscall to events */
337 chan
->sc_table
= kzalloc(sizeof(struct lttng_event
*)
338 * ARRAY_SIZE(sc_table
), GFP_KERNEL
);
344 if (!chan
->compat_sc_table
) {
345 /* create syscall table mapping compat syscall to events */
346 chan
->compat_sc_table
= kzalloc(sizeof(struct lttng_event
*)
347 * ARRAY_SIZE(compat_sc_table
), GFP_KERNEL
);
348 if (!chan
->compat_sc_table
)
352 if (!chan
->sc_unknown
) {
353 const struct lttng_event_desc
*desc
=
354 &__event_desc___sys_unknown
;
356 memset(&ev
, 0, sizeof(ev
));
357 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
358 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
359 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
360 chan
->sc_unknown
= lttng_event_create(chan
, &ev
, filter
,
362 if (!chan
->sc_unknown
) {
367 if (!chan
->sc_compat_unknown
) {
368 const struct lttng_event_desc
*desc
=
369 &__event_desc___compat_sys_unknown
;
371 memset(&ev
, 0, sizeof(ev
));
372 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
373 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
374 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
375 chan
->sc_compat_unknown
= lttng_event_create(chan
, &ev
, filter
,
377 if (!chan
->sc_compat_unknown
) {
382 if (!chan
->sc_exit
) {
383 const struct lttng_event_desc
*desc
=
384 &__event_desc___exit_syscall
;
386 memset(&ev
, 0, sizeof(ev
));
387 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
388 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
389 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
390 chan
->sc_exit
= lttng_event_create(chan
, &ev
, filter
,
392 if (!chan
->sc_exit
) {
397 ret
= fill_table(sc_table
, ARRAY_SIZE(sc_table
),
398 chan
->sc_table
, chan
, filter
);
402 ret
= fill_table(compat_sc_table
, ARRAY_SIZE(compat_sc_table
),
403 chan
->compat_sc_table
, chan
, filter
);
407 ret
= tracepoint_probe_register("sys_enter",
408 (void *) syscall_entry_probe
, chan
);
412 * We change the name of sys_exit tracepoint due to namespace
413 * conflict with sys_exit syscall entry.
415 ret
= tracepoint_probe_register("sys_exit",
416 (void *) __event_probe__exit_syscall
,
419 WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
420 (void *) syscall_entry_probe
, chan
));
426 * Only called at session destruction.
428 int lttng_syscalls_unregister(struct lttng_channel
*chan
)
434 ret
= tracepoint_probe_unregister("sys_exit",
435 (void *) __event_probe__exit_syscall
,
439 ret
= tracepoint_probe_unregister("sys_enter",
440 (void *) syscall_entry_probe
, chan
);
443 /* lttng_event destroy will be performed by lttng_session_destroy() */
444 kfree(chan
->sc_table
);
446 kfree(chan
->compat_sc_table
);