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 <asm/ptrace.h>
28 #include <asm/syscall.h>
30 #include "wrapper/tracepoint.h"
31 #include "lttng-events.h"
34 # ifndef is_compat_task
35 # define is_compat_task() (0)
40 void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
);
43 * Forward declarations for old kernels.
47 struct oldold_utsname
;
49 struct sel_arg_struct
;
50 struct mmap_arg_struct
;
53 * Take care of NOARGS not supported by mainline.
55 #define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
56 #define DEFINE_EVENT_NOARGS(template, name)
57 #define TRACE_EVENT_NOARGS(name, struct, assign, print)
60 * Create LTTng tracepoint probes.
62 #define LTTNG_PACKAGE_BUILD
63 #define CREATE_TRACE_POINTS
64 #define TP_MODULE_NOINIT
65 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
67 #define PARAMS(args...) args
69 /* Hijack probe callback for system calls */
71 #define TP_PROBE_CB(_template) &syscall_entry_probe
72 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
73 TRACE_EVENT(_name, PARAMS(_proto), PARAMS(_args),\
74 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
75 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
76 DECLARE_EVENT_CLASS_NOARGS(_name, PARAMS(_struct), PARAMS(_assign),\
78 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
79 DEFINE_EVENT_NOARGS(_template, _name)
81 #define TRACE_SYSTEM syscalls_integers
82 #include "instrumentation/syscalls/headers/syscalls_integers.h"
84 #define TRACE_SYSTEM syscalls_pointers
85 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
88 #undef SC_DECLARE_EVENT_CLASS_NOARGS
89 #undef SC_DEFINE_EVENT_NOARGS
91 #define TRACE_SYSTEM syscalls_unknown
92 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
95 /* For compat syscalls */
96 #undef _TRACE_SYSCALLS_integers_H
97 #undef _TRACE_SYSCALLS_pointers_H
99 /* Hijack probe callback for system calls */
101 #define TP_PROBE_CB(_template) &syscall_entry_probe
102 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
103 TRACE_EVENT(compat_##_name, PARAMS(_proto), PARAMS(_args), \
104 PARAMS(_struct), PARAMS(_assign), \
106 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
107 DECLARE_EVENT_CLASS_NOARGS(compat_##_name, PARAMS(_struct), \
108 PARAMS(_assign), PARAMS(_printk))
109 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
110 DEFINE_EVENT_NOARGS(compat_##_template, compat_##_name)
111 #define TRACE_SYSTEM compat_syscalls_integers
112 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
114 #define TRACE_SYSTEM compat_syscalls_pointers
115 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
117 #undef SC_TRACE_EVENT
118 #undef SC_DECLARE_EVENT_CLASS_NOARGS
119 #undef SC_DEFINE_EVENT_NOARGS
122 #undef TP_MODULE_NOINIT
123 #undef LTTNG_PACKAGE_BUILD
124 #undef CREATE_TRACE_POINTS
126 struct trace_syscall_entry
{
128 const struct lttng_event_desc
*desc
;
129 const struct lttng_event_field
*fields
;
133 #define CREATE_SYSCALL_TABLE
135 #undef TRACE_SYSCALL_TABLE
136 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
138 .func = __event_probe__##_template, \
139 .nrargs = (_nrargs), \
140 .fields = __event_fields___##_template, \
141 .desc = &__event_desc___##_name, \
144 static const struct trace_syscall_entry sc_table
[] = {
145 #include "instrumentation/syscalls/headers/syscalls_integers.h"
146 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
149 #undef TRACE_SYSCALL_TABLE
150 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
152 .func = __event_probe__##compat_##_template, \
153 .nrargs = (_nrargs), \
154 .fields = __event_fields___##compat_##_template,\
155 .desc = &__event_desc___##compat_##_name, \
158 /* Create compatibility syscall table */
159 const struct trace_syscall_entry compat_sc_table
[] = {
160 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
161 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
164 #undef CREATE_SYSCALL_TABLE
166 static void syscall_entry_unknown(struct lttng_event
*event
,
167 struct pt_regs
*regs
, unsigned int id
)
169 unsigned long args
[UNKNOWN_SYSCALL_NRARGS
];
171 syscall_get_arguments(current
, regs
, 0, UNKNOWN_SYSCALL_NRARGS
, args
);
172 if (unlikely(is_compat_task()))
173 __event_probe__compat_sys_unknown(event
, id
, args
);
175 __event_probe__sys_unknown(event
, id
, args
);
178 void syscall_entry_probe(void *__data
, struct pt_regs
*regs
, long id
)
180 struct lttng_channel
*chan
= __data
;
181 struct lttng_event
*event
, *unknown_event
;
182 const struct trace_syscall_entry
*table
, *entry
;
185 if (unlikely(is_compat_task())) {
186 table
= compat_sc_table
;
187 table_len
= ARRAY_SIZE(compat_sc_table
);
188 unknown_event
= chan
->sc_compat_unknown
;
191 table_len
= ARRAY_SIZE(sc_table
);
192 unknown_event
= chan
->sc_unknown
;
194 if (unlikely(id
>= table_len
)) {
195 syscall_entry_unknown(unknown_event
, regs
, id
);
198 if (unlikely(is_compat_task()))
199 event
= chan
->compat_sc_table
[id
];
201 event
= chan
->sc_table
[id
];
202 if (unlikely(!event
)) {
203 syscall_entry_unknown(unknown_event
, regs
, id
);
207 WARN_ON_ONCE(!entry
);
209 switch (entry
->nrargs
) {
212 void (*fptr
)(void *__data
) = entry
->func
;
219 void (*fptr
)(void *__data
, unsigned long arg0
) = entry
->func
;
220 unsigned long args
[1];
222 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
223 fptr(event
, args
[0]);
228 void (*fptr
)(void *__data
,
230 unsigned long arg1
) = entry
->func
;
231 unsigned long args
[2];
233 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
234 fptr(event
, args
[0], args
[1]);
239 void (*fptr
)(void *__data
,
242 unsigned long arg2
) = entry
->func
;
243 unsigned long args
[3];
245 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
246 fptr(event
, args
[0], args
[1], args
[2]);
251 void (*fptr
)(void *__data
,
255 unsigned long arg3
) = entry
->func
;
256 unsigned long args
[4];
258 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
259 fptr(event
, args
[0], args
[1], args
[2], args
[3]);
264 void (*fptr
)(void *__data
,
269 unsigned long arg4
) = entry
->func
;
270 unsigned long args
[5];
272 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
273 fptr(event
, args
[0], args
[1], args
[2], args
[3], args
[4]);
278 void (*fptr
)(void *__data
,
284 unsigned long arg5
) = entry
->func
;
285 unsigned long args
[6];
287 syscall_get_arguments(current
, regs
, 0, entry
->nrargs
, args
);
288 fptr(event
, args
[0], args
[1], args
[2],
289 args
[3], args
[4], args
[5]);
297 /* noinline to diminish caller stack size */
299 int fill_table(const struct trace_syscall_entry
*table
, size_t table_len
,
300 struct lttng_event
**chan_table
, struct lttng_channel
*chan
, void *filter
)
302 const struct lttng_event_desc
*desc
;
305 /* Allocate events for each syscall, insert into table */
306 for (i
= 0; i
< table_len
; i
++) {
307 struct lttng_kernel_event ev
;
308 desc
= table
[i
].desc
;
311 /* Unknown syscall */
315 * Skip those already populated by previous failed
316 * register for this channel.
320 memset(&ev
, 0, sizeof(ev
));
321 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
322 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
323 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
324 chan_table
[i
] = lttng_event_create(chan
, &ev
, filter
,
326 WARN_ON_ONCE(!chan_table
[i
]);
327 if (IS_ERR(chan_table
[i
])) {
329 * If something goes wrong in event registration
330 * after the first one, we have no choice but to
331 * leave the previous events in there, until
332 * deleted by session teardown.
334 return PTR_ERR(chan_table
[i
]);
340 int lttng_syscalls_register(struct lttng_channel
*chan
, void *filter
)
342 struct lttng_kernel_event ev
;
345 wrapper_vmalloc_sync_all();
347 if (!chan
->sc_table
) {
348 /* create syscall table mapping syscall to events */
349 chan
->sc_table
= kzalloc(sizeof(struct lttng_event
*)
350 * ARRAY_SIZE(sc_table
), GFP_KERNEL
);
356 if (!chan
->compat_sc_table
) {
357 /* create syscall table mapping compat syscall to events */
358 chan
->compat_sc_table
= kzalloc(sizeof(struct lttng_event
*)
359 * ARRAY_SIZE(compat_sc_table
), GFP_KERNEL
);
360 if (!chan
->compat_sc_table
)
364 if (!chan
->sc_unknown
) {
365 const struct lttng_event_desc
*desc
=
366 &__event_desc___sys_unknown
;
368 memset(&ev
, 0, sizeof(ev
));
369 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
370 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
371 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
372 chan
->sc_unknown
= lttng_event_create(chan
, &ev
, filter
,
374 WARN_ON_ONCE(!chan
->sc_unknown
);
375 if (IS_ERR(chan
->sc_unknown
)) {
376 return PTR_ERR(chan
->sc_unknown
);
380 if (!chan
->sc_compat_unknown
) {
381 const struct lttng_event_desc
*desc
=
382 &__event_desc___compat_sys_unknown
;
384 memset(&ev
, 0, sizeof(ev
));
385 strncpy(ev
.name
, desc
->name
, LTTNG_KERNEL_SYM_NAME_LEN
);
386 ev
.name
[LTTNG_KERNEL_SYM_NAME_LEN
- 1] = '\0';
387 ev
.instrumentation
= LTTNG_KERNEL_NOOP
;
388 chan
->sc_compat_unknown
= lttng_event_create(chan
, &ev
, filter
,
390 WARN_ON_ONCE(!chan
->sc_unknown
);
391 if (IS_ERR(chan
->sc_compat_unknown
)) {
392 return PTR_ERR(chan
->sc_compat_unknown
);
396 if (!chan
->sc_exit
) {
397 const struct lttng_event_desc
*desc
=
398 &__event_desc___exit_syscall
;
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_exit
= lttng_event_create(chan
, &ev
, filter
,
406 WARN_ON_ONCE(!chan
->sc_exit
);
407 if (IS_ERR(chan
->sc_exit
)) {
408 return PTR_ERR(chan
->sc_exit
);
412 ret
= fill_table(sc_table
, ARRAY_SIZE(sc_table
),
413 chan
->sc_table
, chan
, filter
);
417 ret
= fill_table(compat_sc_table
, ARRAY_SIZE(compat_sc_table
),
418 chan
->compat_sc_table
, chan
, filter
);
422 ret
= kabi_2635_tracepoint_probe_register("sys_enter",
423 (void *) syscall_entry_probe
, chan
);
427 * We change the name of sys_exit tracepoint due to namespace
428 * conflict with sys_exit syscall entry.
430 ret
= kabi_2635_tracepoint_probe_register("sys_exit",
431 (void *) __event_probe__exit_syscall
,
434 WARN_ON_ONCE(kabi_2635_tracepoint_probe_unregister("sys_enter",
435 (void *) syscall_entry_probe
, chan
));
441 * Only called at session destruction.
443 int lttng_syscalls_unregister(struct lttng_channel
*chan
)
449 ret
= kabi_2635_tracepoint_probe_unregister("sys_exit",
450 (void *) __event_probe__exit_syscall
,
454 ret
= kabi_2635_tracepoint_probe_unregister("sys_enter",
455 (void *) syscall_entry_probe
, chan
);
458 /* lttng_event destroy will be performed by lttng_session_destroy() */
459 kfree(chan
->sc_table
);
461 kfree(chan
->compat_sc_table
);