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 <linux/err.h>
27 #include <linux/bitmap.h>
28 #include <asm/ptrace.h>
29 #include <asm/syscall.h>
31 #include "wrapper/tracepoint.h"
32 #include "lttng-events.h"
35 # ifndef is_compat_task
36 # define is_compat_task() (0)
41 void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
);
44 * Forward declarations for old kernels.
48 struct oldold_utsname
;
50 struct sel_arg_struct
;
51 struct mmap_arg_struct
;
53 #ifdef IA32_NR_syscalls
54 #define NR_compat_syscalls IA32_NR_syscalls
56 #define NR_compat_syscalls NR_syscalls
60 * Take care of NOARGS not supported by mainline.
62 #define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
63 #define DEFINE_EVENT_NOARGS(template, name)
64 #define TRACE_EVENT_NOARGS(name, struct, assign, print)
67 * Create LTTng tracepoint probes.
69 #define LTTNG_PACKAGE_BUILD
70 #define CREATE_TRACE_POINTS
71 #define TP_MODULE_NOINIT
72 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
74 #define PARAMS(args...) args
76 /* Hijack probe callback for system calls */
78 #define TP_PROBE_CB(_template) &syscall_entry_probe
79 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
80 TRACE_EVENT(_name, PARAMS(_proto), PARAMS(_args),\
81 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
82 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
83 DECLARE_EVENT_CLASS_NOARGS(_name, PARAMS(_struct), PARAMS(_assign),\
85 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
86 DEFINE_EVENT_NOARGS(_template, _name)
88 #define TRACE_SYSTEM syscalls_integers
89 #include "instrumentation/syscalls/headers/syscalls_integers.h"
91 #define TRACE_SYSTEM syscalls_pointers
92 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
95 #undef SC_DECLARE_EVENT_CLASS_NOARGS
96 #undef SC_DEFINE_EVENT_NOARGS
98 #define TRACE_SYSTEM syscalls_unknown
99 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
102 /* For compat syscalls */
103 #undef _TRACE_SYSCALLS_integers_H
104 #undef _TRACE_SYSCALLS_pointers_H
106 /* Hijack probe callback for system calls */
108 #define TP_PROBE_CB(_template) &syscall_entry_probe
109 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
110 TRACE_EVENT(compat_##_name, PARAMS(_proto), PARAMS(_args), \
111 PARAMS(_struct), PARAMS(_assign), \
113 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
114 DECLARE_EVENT_CLASS_NOARGS(compat_##_name, PARAMS(_struct), \
115 PARAMS(_assign), PARAMS(_printk))
116 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
117 DEFINE_EVENT_NOARGS(compat_##_template, compat_##_name)
118 #define TRACE_SYSTEM compat_syscalls_integers
119 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
121 #define TRACE_SYSTEM compat_syscalls_pointers
122 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
124 #undef SC_TRACE_EVENT
125 #undef SC_DECLARE_EVENT_CLASS_NOARGS
126 #undef SC_DEFINE_EVENT_NOARGS
129 #undef TP_MODULE_NOINIT
130 #undef LTTNG_PACKAGE_BUILD
131 #undef CREATE_TRACE_POINTS
133 struct trace_syscall_entry
{
135 const struct lttng_event_desc
*desc
;
136 const struct lttng_event_field
*fields
;
140 #define CREATE_SYSCALL_TABLE
142 #undef TRACE_SYSCALL_TABLE
143 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
145 .func = __event_probe__##_template, \
146 .nrargs = (_nrargs), \
147 .fields = __event_fields___##_template, \
148 .desc = &__event_desc___##_name, \
151 static const struct trace_syscall_entry sc_table
[] = {
152 #include "instrumentation/syscalls/headers/syscalls_integers.h"
153 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
156 #undef TRACE_SYSCALL_TABLE
157 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
159 .func = __event_probe__##compat_##_template, \
160 .nrargs = (_nrargs), \
161 .fields = __event_fields___##compat_##_template,\
162 .desc = &__event_desc___##compat_##_name, \
165 /* Create compatibility syscall table */
166 const struct trace_syscall_entry compat_sc_table
[] = {
167 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
168 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
171 #undef CREATE_SYSCALL_TABLE
173 struct lttng_syscall_filter
{
174 DECLARE_BITMAP(sc
, NR_syscalls
);
175 DECLARE_BITMAP(sc_compat
, NR_compat_syscalls
);
178 static void syscall_entry_unknown(struct lttng_event
*event
,
179 struct pt_regs
*regs
, unsigned int id
)
181 unsigned long args
[UNKNOWN_SYSCALL_NRARGS
];
183 syscall_get_arguments(current
, regs
, 0, UNKNOWN_SYSCALL_NRARGS
, args
);
184 if (unlikely(is_compat_task()))
185 __event_probe__compat_sys_unknown(event
, id
, args
);
187 __event_probe__sys_unknown(event
, id
, args
);
190 void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
)
192 struct lttng_channel
*chan
= __data
;
193 struct lttng_event
*event
, *unknown_event
;
194 const struct trace_syscall_entry
*table
, *entry
;
197 if (unlikely(is_compat_task())) {
198 struct lttng_syscall_filter
*filter
;
200 filter
= rcu_dereference(chan
->sc_filter
);
202 if (id
>= NR_compat_syscalls
203 || !test_bit(id
, filter
->sc_compat
)) {
204 /* System call filtered out. */
208 table
= compat_sc_table
;
209 table_len
= ARRAY_SIZE(compat_sc_table
);
210 unknown_event
= chan
->sc_compat_unknown
;
212 struct lttng_syscall_filter
*filter
;
214 filter
= rcu_dereference(chan
->sc_filter
);
216 if (id
>= NR_syscalls
217 || !test_bit(id
, filter
->sc
)) {
218 /* System call filtered out. */
223 table_len
= ARRAY_SIZE(sc_table
);
224 unknown_event
= chan
->sc_unknown
;
226 if (unlikely(id
>= table_len
)) {
227 syscall_entry_unknown(unknown_event
, regs
, id
);
230 if (unlikely(is_compat_task()))
231 event
= chan
->compat_sc_table
[id
];
233 event
= chan
->sc_table
[id
];
234 if (unlikely(!event
)) {
235 syscall_entry_unknown(unknown_event
, regs
, id
);
239 WARN_ON_ONCE(!entry
);
241 switch (entry
->nrargs
) {
244 void (*fptr
)(void *__data
) = entry
->func
;
251 void (*fptr
)(void *__data
, unsigned long arg0
) = entry
->func
;
252 unsigned long args
[1];
254 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
255 fptr(event
, args
[0]);
260 void (*fptr
)(void *__data
,
262 unsigned long arg1
) = entry
->func
;
263 unsigned long args
[2];
265 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
266 fptr(event
, args
[0], args
[1]);
271 void (*fptr
)(void *__data
,
274 unsigned long arg2
) = entry
->func
;
275 unsigned long args
[3];
277 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
278 fptr(event
, args
[0], args
[1], args
[2]);
283 void (*fptr
)(void *__data
,
287 unsigned long arg3
) = entry
->func
;
288 unsigned long args
[4];
290 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
291 fptr(event
, args
[0], args
[1], args
[2], args
[3]);
296 void (*fptr
)(void *__data
,
301 unsigned long arg4
) = entry
->func
;
302 unsigned long args
[5];
304 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
305 fptr(event
, args
[0], args
[1], args
[2], args
[3], args
[4]);
310 void (*fptr
)(void *__data
,
316 unsigned long arg5
) = entry
->func
;
317 unsigned long args
[6];
319 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
320 fptr(event
, args
[0], args
[1], args
[2],
321 args
[3], args
[4], args
[5]);
329 /* noinline to diminish caller stack size */
331 int fill_table(const struct trace_syscall_entry
*table
, size_t table_len
,
332 struct lttng_event
**chan_table
, struct lttng_channel
*chan
, void *filter
)
334 const struct lttng_event_desc
*desc
;
337 /* Allocate events for each syscall, insert into table */
338 for (i
= 0; i
< table_len
; i
++) {
339 struct lttng_kernel_event ev
;
340 desc
= table
[i
].desc
;
343 /* Unknown syscall */
347 * Skip those already populated by previous failed
348 * register for this channel.
352 memset(&ev
, 0, sizeof(ev
));
353 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
354 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
355 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
356 chan_table
[i
] = lttng_event_create(chan
, &ev
, filter
,
358 WARN_ON_ONCE(!chan_table
[i
]);
359 if (IS_ERR(chan_table
[i
])) {
361 * If something goes wrong in event registration
362 * after the first one, we have no choice but to
363 * leave the previous events in there, until
364 * deleted by session teardown.
366 return PTR_ERR(chan_table
[i
]);
372 int lttng_syscalls_register(struct lttng_channel
*chan
, void *filter
)
374 struct lttng_kernel_event ev
;
377 wrapper_vmalloc_sync_all();
379 if (!chan
->sc_table
) {
380 /* create syscall table mapping syscall to events */
381 chan
->sc_table
= kzalloc(sizeof(struct lttng_event
*)
382 * ARRAY_SIZE(sc_table
), GFP_KERNEL
);
388 if (!chan
->compat_sc_table
) {
389 /* create syscall table mapping compat syscall to events */
390 chan
->compat_sc_table
= kzalloc(sizeof(struct lttng_event
*)
391 * ARRAY_SIZE(compat_sc_table
), GFP_KERNEL
);
392 if (!chan
->compat_sc_table
)
396 if (!chan
->sc_unknown
) {
397 const struct lttng_event_desc
*desc
=
398 &__event_desc___sys_unknown
;
400 memset(&ev
, 0, sizeof(ev
));
401 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
402 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
403 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
404 chan
->sc_unknown
= lttng_event_create(chan
, &ev
, filter
,
406 WARN_ON_ONCE(!chan
->sc_unknown
);
407 if (IS_ERR(chan
->sc_unknown
)) {
408 return PTR_ERR(chan
->sc_unknown
);
412 if (!chan
->sc_compat_unknown
) {
413 const struct lttng_event_desc
*desc
=
414 &__event_desc___compat_sys_unknown
;
416 memset(&ev
, 0, sizeof(ev
));
417 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
418 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
419 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
420 chan
->sc_compat_unknown
= lttng_event_create(chan
, &ev
, filter
,
422 WARN_ON_ONCE(!chan
->sc_unknown
);
423 if (IS_ERR(chan
->sc_compat_unknown
)) {
424 return PTR_ERR(chan
->sc_compat_unknown
);
428 if (!chan
->sc_exit
) {
429 const struct lttng_event_desc
*desc
=
430 &__event_desc___exit_syscall
;
432 memset(&ev
, 0, sizeof(ev
));
433 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
434 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
435 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
436 chan
->sc_exit
= lttng_event_create(chan
, &ev
, filter
,
438 WARN_ON_ONCE(!chan
->sc_exit
);
439 if (IS_ERR(chan
->sc_exit
)) {
440 return PTR_ERR(chan
->sc_exit
);
444 ret
= fill_table(sc_table
, ARRAY_SIZE(sc_table
),
445 chan
->sc_table
, chan
, filter
);
449 ret
= fill_table(compat_sc_table
, ARRAY_SIZE(compat_sc_table
),
450 chan
->compat_sc_table
, chan
, filter
);
454 if (!chan
->sys_enter_registered
) {
455 ret
= lttng_wrapper_tracepoint_probe_register("sys_enter",
456 (void *) syscall_entry_probe
, chan
);
459 chan
->sys_enter_registered
= 1;
462 * We change the name of sys_exit tracepoint due to namespace
463 * conflict with sys_exit syscall entry.
465 if (!chan
->sys_exit_registered
) {
466 ret
= lttng_wrapper_tracepoint_probe_register("sys_exit",
467 (void *) __event_probe__exit_syscall
,
470 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
471 (void *) syscall_entry_probe
, chan
));
474 chan
->sys_exit_registered
= 1;
480 * Only called at session destruction.
482 int lttng_syscalls_unregister(struct lttng_channel
*chan
)
488 if (chan
->sys_enter_registered
) {
489 ret
= lttng_wrapper_tracepoint_probe_unregister("sys_exit",
490 (void *) __event_probe__exit_syscall
,
494 chan
->sys_enter_registered
= 0;
496 if (chan
->sys_exit_registered
) {
497 ret
= lttng_wrapper_tracepoint_probe_unregister("sys_enter",
498 (void *) syscall_entry_probe
, chan
);
501 chan
->sys_exit_registered
= 0;
503 /* lttng_event destroy will be performed by lttng_session_destroy() */
504 kfree(chan
->sc_table
);
506 kfree(chan
->compat_sc_table
);
508 kfree(chan
->sc_filter
);
513 int get_syscall_nr(const char *syscall_name
)
518 for (i
= 0; i
< ARRAY_SIZE(sc_table
); i
++) {
519 const struct trace_syscall_entry
*entry
;
521 entry
= &sc_table
[i
];
524 if (!strcmp(syscall_name
, entry
->desc
->name
)) {
533 int get_compat_syscall_nr(const char *syscall_name
)
538 for (i
= 0; i
< ARRAY_SIZE(compat_sc_table
); i
++) {
539 const struct trace_syscall_entry
*entry
;
541 entry
= &compat_sc_table
[i
];
544 if (!strcmp(syscall_name
, entry
->desc
->name
)) {
552 int lttng_syscall_filter_enable(struct lttng_channel
*chan
,
555 int syscall_nr
, compat_syscall_nr
, ret
;
556 struct lttng_syscall_filter
*filter
;
558 WARN_ON_ONCE(!chan
->sc_table
);
561 /* Enable all system calls by removing filter */
562 if (chan
->sc_filter
) {
563 filter
= chan
->sc_filter
;
564 rcu_assign_pointer(chan
->sc_filter
, NULL
);
568 chan
->syscall_all
= 1;
572 if (!chan
->sc_filter
) {
573 if (chan
->syscall_all
) {
575 * All syscalls are already enabled.
579 filter
= kzalloc(sizeof(struct lttng_syscall_filter
),
584 filter
= chan
->sc_filter
;
586 syscall_nr
= get_syscall_nr(name
);
587 compat_syscall_nr
= get_compat_syscall_nr(name
);
588 if (syscall_nr
< 0 && compat_syscall_nr
< 0) {
592 if (syscall_nr
>= 0) {
593 if (test_bit(syscall_nr
, filter
->sc
)) {
597 bitmap_set(filter
->sc
, syscall_nr
, 1);
599 if (compat_syscall_nr
>= 0) {
600 if (test_bit(compat_syscall_nr
, filter
->sc_compat
)) {
604 bitmap_set(filter
->sc_compat
, compat_syscall_nr
, 1);
606 if (!chan
->sc_filter
)
607 rcu_assign_pointer(chan
->sc_filter
, filter
);
611 if (!chan
->sc_filter
)
616 int lttng_syscall_filter_disable(struct lttng_channel
*chan
,
619 int syscall_nr
, compat_syscall_nr
, ret
;
620 struct lttng_syscall_filter
*filter
;
622 WARN_ON_ONCE(!chan
->sc_table
);
624 if (!chan
->sc_filter
) {
625 filter
= kzalloc(sizeof(struct lttng_syscall_filter
),
629 /* Trace all system calls, then apply disable. */
630 bitmap_set(filter
->sc
, 0, NR_syscalls
);
631 bitmap_set(filter
->sc_compat
, 0, NR_compat_syscalls
);
633 filter
= chan
->sc_filter
;
636 syscall_nr
= get_syscall_nr(name
);
637 compat_syscall_nr
= get_compat_syscall_nr(name
);
638 if (syscall_nr
< 0 && compat_syscall_nr
< 0) {
642 if (syscall_nr
>= 0) {
643 if (!test_bit(syscall_nr
, chan
->sc_filter
->sc
)) {
647 bitmap_clear(chan
->sc_filter
->sc
, syscall_nr
, 1);
649 if (compat_syscall_nr
>= 0) {
650 if (!test_bit(compat_syscall_nr
, chan
->sc_filter
->sc_compat
)) {
654 bitmap_clear(chan
->sc_filter
->sc_compat
, compat_syscall_nr
, 1);
656 if (!chan
->sc_filter
)
657 rcu_assign_pointer(chan
->sc_filter
, filter
);
658 chan
->syscall_all
= 0;
662 if (!chan
->sc_filter
)