Version 2.5.6
[lttng-modules.git] / lttng-syscalls.c
CommitLineData
259b6cb3
MD
1/*
2 * lttng-syscalls.c
3 *
2faf7d1b 4 * LTTng syscall probes.
259b6cb3 5 *
886d51a3
MD
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
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.
12 *
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.
17 *
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
259b6cb3
MD
21 */
22
23#include <linux/module.h>
24#include <linux/slab.h>
6333ace3 25#include <linux/compat.h>
abc0446a 26#include <linux/err.h>
259b6cb3
MD
27#include <asm/ptrace.h>
28#include <asm/syscall.h>
29
3a523f5b 30#include "wrapper/tracepoint.h"
a90917c3 31#include "lttng-events.h"
259b6cb3 32
6333ace3 33#ifndef CONFIG_COMPAT
bfa949bf
MD
34# ifndef is_compat_task
35# define is_compat_task() (0)
36# endif
6333ace3
MD
37#endif
38
a93244f8 39static
2faf7d1b 40void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
259b6cb3 41
3a523f5b
MD
42/*
43 * Forward declarations for old kernels.
44 */
45struct mmsghdr;
46struct rlimit64;
47struct oldold_utsname;
48struct old_utsname;
49struct sel_arg_struct;
50struct mmap_arg_struct;
50cd7500 51struct file_handle;
3a523f5b 52
f7bdf4db
MD
53/*
54 * Take care of NOARGS not supported by mainline.
55 */
56#define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
57#define DEFINE_EVENT_NOARGS(template, name)
58#define TRACE_EVENT_NOARGS(name, struct, assign, print)
59
259b6cb3
MD
60/*
61 * Create LTTng tracepoint probes.
62 */
63#define LTTNG_PACKAGE_BUILD
64#define CREATE_TRACE_POINTS
2655f9ad 65#define TP_MODULE_NOINIT
2f804c0a 66#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
259b6cb3 67
a93244f8
MD
68#define PARAMS(args...) args
69
259b6cb3 70/* Hijack probe callback for system calls */
a93244f8 71#undef TP_PROBE_CB
259b6cb3 72#define TP_PROBE_CB(_template) &syscall_entry_probe
a93244f8
MD
73#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
74 TRACE_EVENT(_name, PARAMS(_proto), PARAMS(_args),\
75 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
76#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
77 DECLARE_EVENT_CLASS_NOARGS(_name, PARAMS(_struct), PARAMS(_assign),\
78 PARAMS(_printk))
79#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
80 DEFINE_EVENT_NOARGS(_template, _name)
81#undef TRACE_SYSTEM
82#define TRACE_SYSTEM syscalls_integers
177b3692 83#include "instrumentation/syscalls/headers/syscalls_integers.h"
a93244f8
MD
84#undef TRACE_SYSTEM
85#define TRACE_SYSTEM syscalls_pointers
177b3692 86#include "instrumentation/syscalls/headers/syscalls_pointers.h"
a93244f8
MD
87#undef TRACE_SYSTEM
88#undef SC_TRACE_EVENT
89#undef SC_DECLARE_EVENT_CLASS_NOARGS
90#undef SC_DEFINE_EVENT_NOARGS
2f804c0a 91
a93244f8 92#define TRACE_SYSTEM syscalls_unknown
63728b02 93#include "instrumentation/syscalls/headers/syscalls_unknown.h"
a93244f8
MD
94#undef TRACE_SYSTEM
95
96/* For compat syscalls */
97#undef _TRACE_SYSCALLS_integers_H
98#undef _TRACE_SYSCALLS_pointers_H
99
100/* Hijack probe callback for system calls */
101#undef TP_PROBE_CB
102#define TP_PROBE_CB(_template) &syscall_entry_probe
103#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
104 TRACE_EVENT(compat_##_name, PARAMS(_proto), PARAMS(_args), \
105 PARAMS(_struct), PARAMS(_assign), \
106 PARAMS(_printk))
107#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
108 DECLARE_EVENT_CLASS_NOARGS(compat_##_name, PARAMS(_struct), \
109 PARAMS(_assign), PARAMS(_printk))
110#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
111 DEFINE_EVENT_NOARGS(compat_##_template, compat_##_name)
112#define TRACE_SYSTEM compat_syscalls_integers
113#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
114#undef TRACE_SYSTEM
115#define TRACE_SYSTEM compat_syscalls_pointers
116#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
117#undef TRACE_SYSTEM
118#undef SC_TRACE_EVENT
119#undef SC_DECLARE_EVENT_CLASS_NOARGS
120#undef SC_DEFINE_EVENT_NOARGS
121#undef TP_PROBE_CB
259b6cb3 122
2655f9ad 123#undef TP_MODULE_NOINIT
259b6cb3
MD
124#undef LTTNG_PACKAGE_BUILD
125#undef CREATE_TRACE_POINTS
126
a93244f8
MD
127struct trace_syscall_entry {
128 void *func;
129 const struct lttng_event_desc *desc;
130 const struct lttng_event_field *fields;
131 unsigned int nrargs;
132};
133
134#define CREATE_SYSCALL_TABLE
135
259b6cb3 136#undef TRACE_SYSCALL_TABLE
f7bdf4db 137#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259b6cb3 138 [ _nr ] = { \
f7bdf4db 139 .func = __event_probe__##_template, \
259b6cb3 140 .nrargs = (_nrargs), \
f7bdf4db
MD
141 .fields = __event_fields___##_template, \
142 .desc = &__event_desc___##_name, \
259b6cb3
MD
143 },
144
49c50022 145static const struct trace_syscall_entry sc_table[] = {
177b3692
MD
146#include "instrumentation/syscalls/headers/syscalls_integers.h"
147#include "instrumentation/syscalls/headers/syscalls_pointers.h"
259b6cb3
MD
148};
149
a93244f8
MD
150#undef TRACE_SYSCALL_TABLE
151#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
152 [ _nr ] = { \
153 .func = __event_probe__##compat_##_template, \
154 .nrargs = (_nrargs), \
155 .fields = __event_fields___##compat_##_template,\
156 .desc = &__event_desc___##compat_##_name, \
157 },
158
159/* Create compatibility syscall table */
160const struct trace_syscall_entry compat_sc_table[] = {
161#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
162#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
163};
259b6cb3 164
a93244f8 165#undef CREATE_SYSCALL_TABLE
2faf7d1b 166
a90917c3 167static void syscall_entry_unknown(struct lttng_event *event,
f405cfce
MD
168 struct pt_regs *regs, unsigned int id)
169{
170 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
f405cfce 171
f405cfce 172 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
a93244f8
MD
173 if (unlikely(is_compat_task()))
174 __event_probe__compat_sys_unknown(event, id, args);
175 else
176 __event_probe__sys_unknown(event, id, args);
f405cfce
MD
177}
178
2faf7d1b 179void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
259b6cb3 180{
a90917c3
MD
181 struct lttng_channel *chan = __data;
182 struct lttng_event *event, *unknown_event;
49c50022
MD
183 const struct trace_syscall_entry *table, *entry;
184 size_t table_len;
259b6cb3 185
b76dc1a0 186 if (unlikely(is_compat_task())) {
49c50022 187 table = compat_sc_table;
a93244f8 188 table_len = ARRAY_SIZE(compat_sc_table);
49c50022
MD
189 unknown_event = chan->sc_compat_unknown;
190 } else {
191 table = sc_table;
192 table_len = ARRAY_SIZE(sc_table);
193 unknown_event = chan->sc_unknown;
b76dc1a0 194 }
49c50022
MD
195 if (unlikely(id >= table_len)) {
196 syscall_entry_unknown(unknown_event, regs, id);
259b6cb3 197 return;
f405cfce 198 }
49c50022
MD
199 if (unlikely(is_compat_task()))
200 event = chan->compat_sc_table[id];
201 else
202 event = chan->sc_table[id];
f405cfce 203 if (unlikely(!event)) {
49c50022 204 syscall_entry_unknown(unknown_event, regs, id);
f405cfce
MD
205 return;
206 }
49c50022 207 entry = &table[id];
f405cfce 208 WARN_ON_ONCE(!entry);
259b6cb3
MD
209
210 switch (entry->nrargs) {
211 case 0:
212 {
213 void (*fptr)(void *__data) = entry->func;
214
215 fptr(event);
216 break;
217 }
218 case 1:
219 {
220 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
221 unsigned long args[1];
222
223 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
224 fptr(event, args[0]);
225 break;
226 }
227 case 2:
228 {
229 void (*fptr)(void *__data,
230 unsigned long arg0,
231 unsigned long arg1) = entry->func;
232 unsigned long args[2];
233
234 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
235 fptr(event, args[0], args[1]);
236 break;
237 }
238 case 3:
239 {
240 void (*fptr)(void *__data,
241 unsigned long arg0,
242 unsigned long arg1,
243 unsigned long arg2) = entry->func;
244 unsigned long args[3];
245
246 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
247 fptr(event, args[0], args[1], args[2]);
248 break;
249 }
250 case 4:
251 {
252 void (*fptr)(void *__data,
253 unsigned long arg0,
254 unsigned long arg1,
255 unsigned long arg2,
256 unsigned long arg3) = entry->func;
257 unsigned long args[4];
258
259 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
260 fptr(event, args[0], args[1], args[2], args[3]);
261 break;
262 }
263 case 5:
264 {
265 void (*fptr)(void *__data,
266 unsigned long arg0,
267 unsigned long arg1,
268 unsigned long arg2,
269 unsigned long arg3,
270 unsigned long arg4) = entry->func;
271 unsigned long args[5];
272
273 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
274 fptr(event, args[0], args[1], args[2], args[3], args[4]);
275 break;
276 }
277 case 6:
278 {
279 void (*fptr)(void *__data,
280 unsigned long arg0,
281 unsigned long arg1,
282 unsigned long arg2,
283 unsigned long arg3,
284 unsigned long arg4,
285 unsigned long arg5) = entry->func;
286 unsigned long args[6];
287
288 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
289 fptr(event, args[0], args[1], args[2],
290 args[3], args[4], args[5]);
291 break;
292 }
293 default:
294 break;
295 }
296}
297
2a0c4816 298/* noinline to diminish caller stack size */
49c50022
MD
299static
300int fill_table(const struct trace_syscall_entry *table, size_t table_len,
a90917c3 301 struct lttng_event **chan_table, struct lttng_channel *chan, void *filter)
259b6cb3 302{
2a0c4816 303 const struct lttng_event_desc *desc;
259b6cb3 304 unsigned int i;
49c50022
MD
305
306 /* Allocate events for each syscall, insert into table */
307 for (i = 0; i < table_len; i++) {
308 struct lttng_kernel_event ev;
2a0c4816 309 desc = table[i].desc;
49c50022
MD
310
311 if (!desc) {
312 /* Unknown syscall */
313 continue;
314 }
315 /*
316 * Skip those already populated by previous failed
317 * register for this channel.
318 */
319 if (chan_table[i])
320 continue;
321 memset(&ev, 0, sizeof(ev));
f8695253
MD
322 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
323 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
49c50022 324 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 325 chan_table[i] = lttng_event_create(chan, &ev, filter,
49c50022 326 desc);
abc0446a
MD
327 WARN_ON_ONCE(!chan_table[i]);
328 if (IS_ERR(chan_table[i])) {
49c50022
MD
329 /*
330 * If something goes wrong in event registration
331 * after the first one, we have no choice but to
332 * leave the previous events in there, until
333 * deleted by session teardown.
334 */
abc0446a 335 return PTR_ERR(chan_table[i]);
49c50022
MD
336 }
337 }
338 return 0;
339}
340
a90917c3 341int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
49c50022 342{
2a0c4816 343 struct lttng_kernel_event ev;
259b6cb3
MD
344 int ret;
345
346 wrapper_vmalloc_sync_all();
259b6cb3
MD
347
348 if (!chan->sc_table) {
349 /* create syscall table mapping syscall to events */
a90917c3 350 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
259b6cb3
MD
351 * ARRAY_SIZE(sc_table), GFP_KERNEL);
352 if (!chan->sc_table)
353 return -ENOMEM;
354 }
355
49c50022
MD
356#ifdef CONFIG_COMPAT
357 if (!chan->compat_sc_table) {
358 /* create syscall table mapping compat syscall to events */
a90917c3 359 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
a93244f8 360 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
49c50022
MD
361 if (!chan->compat_sc_table)
362 return -ENOMEM;
363 }
364#endif
f405cfce 365 if (!chan->sc_unknown) {
f405cfce
MD
366 const struct lttng_event_desc *desc =
367 &__event_desc___sys_unknown;
2f804c0a 368
f405cfce 369 memset(&ev, 0, sizeof(ev));
f8695253
MD
370 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
371 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
f405cfce 372 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 373 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
f405cfce 374 desc);
abc0446a
MD
375 WARN_ON_ONCE(!chan->sc_unknown);
376 if (IS_ERR(chan->sc_unknown)) {
377 return PTR_ERR(chan->sc_unknown);
f405cfce
MD
378 }
379 }
380
b76dc1a0 381 if (!chan->sc_compat_unknown) {
b76dc1a0
MD
382 const struct lttng_event_desc *desc =
383 &__event_desc___compat_sys_unknown;
384
385 memset(&ev, 0, sizeof(ev));
f8695253
MD
386 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
387 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
b76dc1a0 388 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 389 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
b76dc1a0 390 desc);
abc0446a
MD
391 WARN_ON_ONCE(!chan->sc_unknown);
392 if (IS_ERR(chan->sc_compat_unknown)) {
393 return PTR_ERR(chan->sc_compat_unknown);
b76dc1a0
MD
394 }
395 }
396
2f804c0a 397 if (!chan->sc_exit) {
2f804c0a
MD
398 const struct lttng_event_desc *desc =
399 &__event_desc___exit_syscall;
400
401 memset(&ev, 0, sizeof(ev));
f8695253
MD
402 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
403 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
2f804c0a 404 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 405 chan->sc_exit = lttng_event_create(chan, &ev, filter,
2f804c0a 406 desc);
abc0446a
MD
407 WARN_ON_ONCE(!chan->sc_exit);
408 if (IS_ERR(chan->sc_exit)) {
409 return PTR_ERR(chan->sc_exit);
2f804c0a
MD
410 }
411 }
412
49c50022
MD
413 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
414 chan->sc_table, chan, filter);
415 if (ret)
416 return ret;
417#ifdef CONFIG_COMPAT
a93244f8 418 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
49c50022
MD
419 chan->compat_sc_table, chan, filter);
420 if (ret)
421 return ret;
422#endif
20591cf7 423 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
259b6cb3 424 (void *) syscall_entry_probe, chan);
63728b02
MD
425 if (ret)
426 return ret;
427 /*
428 * We change the name of sys_exit tracepoint due to namespace
429 * conflict with sys_exit syscall entry.
430 */
20591cf7 431 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
2c01ec07 432 (void *) __event_probe__exit_syscall,
2f804c0a 433 chan->sc_exit);
63728b02 434 if (ret) {
20591cf7 435 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
63728b02
MD
436 (void *) syscall_entry_probe, chan));
437 }
259b6cb3
MD
438 return ret;
439}
440
441/*
442 * Only called at session destruction.
443 */
a90917c3 444int lttng_syscalls_unregister(struct lttng_channel *chan)
259b6cb3
MD
445{
446 int ret;
447
448 if (!chan->sc_table)
449 return 0;
20591cf7 450 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
2c01ec07 451 (void *) __event_probe__exit_syscall,
2f804c0a 452 chan->sc_exit);
63728b02
MD
453 if (ret)
454 return ret;
20591cf7 455 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
259b6cb3
MD
456 (void *) syscall_entry_probe, chan);
457 if (ret)
458 return ret;
a90917c3 459 /* lttng_event destroy will be performed by lttng_session_destroy() */
259b6cb3 460 kfree(chan->sc_table);
49c50022
MD
461#ifdef CONFIG_COMPAT
462 kfree(chan->compat_sc_table);
463#endif
259b6cb3
MD
464 return 0;
465}
This page took 0.047428 seconds and 4 git commands to generate.