Update syscall inout table
[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>
80f87dd2 27#include <linux/bitmap.h>
259b6cb3
MD
28#include <asm/ptrace.h>
29#include <asm/syscall.h>
30
3a523f5b 31#include "wrapper/tracepoint.h"
a90917c3 32#include "lttng-events.h"
259b6cb3 33
6333ace3 34#ifndef CONFIG_COMPAT
bfa949bf
MD
35# ifndef is_compat_task
36# define is_compat_task() (0)
37# endif
6333ace3
MD
38#endif
39
5b7ac358
MD
40enum sc_type {
41 SC_TYPE_ENTRY,
42 SC_TYPE_EXIT,
43 SC_TYPE_COMPAT_ENTRY,
44 SC_TYPE_COMPAT_EXIT,
45};
46
47#define SYSCALL_ENTRY_STR "syscall_entry_"
48#define COMPAT_SYSCALL_ENTRY_STR "compat_syscall_entry_"
49#define SYSCALL_EXIT_STR "syscall_exit_"
50#define COMPAT_SYSCALL_EXIT_STR "compat_syscall_exit_"
51
a93244f8 52static
2faf7d1b 53void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
5b7ac358
MD
54static
55void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
259b6cb3 56
3a523f5b
MD
57/*
58 * Forward declarations for old kernels.
59 */
60struct mmsghdr;
61struct rlimit64;
62struct oldold_utsname;
63struct old_utsname;
64struct sel_arg_struct;
65struct mmap_arg_struct;
66
80f87dd2
MD
67#ifdef IA32_NR_syscalls
68#define NR_compat_syscalls IA32_NR_syscalls
69#else
70#define NR_compat_syscalls NR_syscalls
71#endif
72
f7bdf4db
MD
73/*
74 * Take care of NOARGS not supported by mainline.
75 */
76#define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
77#define DEFINE_EVENT_NOARGS(template, name)
78#define TRACE_EVENT_NOARGS(name, struct, assign, print)
79
259b6cb3
MD
80/*
81 * Create LTTng tracepoint probes.
82 */
83#define LTTNG_PACKAGE_BUILD
84#define CREATE_TRACE_POINTS
2655f9ad 85#define TP_MODULE_NOINIT
2f804c0a 86#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
259b6cb3 87
a93244f8
MD
88#define PARAMS(args...) args
89
5b7ac358
MD
90/* Handle unknown syscalls */
91#define TRACE_SYSTEM syscalls_unknown
92#include "instrumentation/syscalls/headers/syscalls_unknown.h"
93#undef TRACE_SYSTEM
94
fc4f7161
MD
95#define SC_ENTER
96
97#undef SC_EXIT_PROTO
98#define SC_EXIT_PROTO(...)
99#undef SC_EXIT_ARGS
100#define SC_EXIT_ARGS(...)
101#undef sc_exit
102#define sc_exit(...)
5b7ac358
MD
103
104/* Hijack probe callback for system call enter */
a93244f8 105#undef TP_PROBE_CB
259b6cb3 106#define TP_PROBE_CB(_template) &syscall_entry_probe
a93244f8 107#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 108 TRACE_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
a93244f8
MD
109 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
110#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358 111 DECLARE_EVENT_CLASS_NOARGS(syscall_enter_##_name, PARAMS(_struct), PARAMS(_assign),\
a93244f8
MD
112 PARAMS(_printk))
113#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358 114 DEFINE_EVENT_NOARGS(syscall_enter_##_template, syscall_enter_##_name)
a93244f8 115#undef TRACE_SYSTEM
5b7ac358
MD
116#define TRACE_SYSTEM syscall_enter_integers
117#define TRACE_INCLUDE_FILE syscalls_integers
177b3692 118#include "instrumentation/syscalls/headers/syscalls_integers.h"
5b7ac358 119#undef TRACE_INCLUDE_FILE
a93244f8 120#undef TRACE_SYSTEM
5b7ac358
MD
121#define TRACE_SYSTEM syscall_enter_pointers
122#define TRACE_INCLUDE_FILE syscalls_pointers
177b3692 123#include "instrumentation/syscalls/headers/syscalls_pointers.h"
5b7ac358 124#undef TRACE_INCLUDE_FILE
a93244f8
MD
125#undef TRACE_SYSTEM
126#undef SC_TRACE_EVENT
127#undef SC_DECLARE_EVENT_CLASS_NOARGS
128#undef SC_DEFINE_EVENT_NOARGS
5b7ac358 129#undef TP_PROBE_CB
a93244f8
MD
130#undef _TRACE_SYSCALLS_integers_H
131#undef _TRACE_SYSCALLS_pointers_H
132
5b7ac358
MD
133
134/* Hijack probe callback for compat system call enter */
a93244f8
MD
135#define TP_PROBE_CB(_template) &syscall_entry_probe
136#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 137 TRACE_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
a93244f8
MD
138 PARAMS(_struct), PARAMS(_assign), \
139 PARAMS(_printk))
140#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358
MD
141 DECLARE_EVENT_CLASS_NOARGS(compat_syscall_enter_##_name, PARAMS(_struct), \
142 PARAMS(_assign), PARAMS(_printk))
143#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
144 DEFINE_EVENT_NOARGS(compat_syscall_enter_##_template, \
145 compat_syscall_enter_##_name)
146#define TRACE_SYSTEM compat_syscall_enter_integers
147#define TRACE_INCLUDE_FILE compat_syscalls_integers
148#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
149#undef TRACE_INCLUDE_FILE
150#undef TRACE_SYSTEM
151#define TRACE_SYSTEM compat_syscall_enter_pointers
152#define TRACE_INCLUDE_FILE compat_syscalls_pointers
153#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
154#undef TRACE_INCLUDE_FILE
155#undef TRACE_SYSTEM
156#undef SC_TRACE_EVENT
157#undef SC_DECLARE_EVENT_CLASS_NOARGS
158#undef SC_DEFINE_EVENT_NOARGS
159#undef TP_PROBE_CB
160#undef _TRACE_SYSCALLS_integers_H
161#undef _TRACE_SYSCALLS_pointers_H
162
fc4f7161
MD
163#undef SC_ENTER
164
165#define SC_EXIT
166
167#undef SC_EXIT_PROTO
168#define SC_EXIT_PROTO(...) __VA_ARGS__
169#undef SC_EXIT_ARGS
170#define SC_EXIT_ARGS(...) __VA_ARGS__
171#undef sc_exit
172#define sc_exit(...) __VA_ARGS__
5b7ac358
MD
173
174/* Hijack probe callback for system call exit */
175#define TP_PROBE_CB(_template) &syscall_exit_probe
176#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
177 TRACE_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args),\
178 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
179#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
180 DECLARE_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_struct), \
181 PARAMS(_assign), PARAMS(_printk))
182#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
183 DEFINE_EVENT_NOARGS(syscall_exit_##_template, \
184 syscall_exit_##_name)
185#define TRACE_SYSTEM syscall_exit_integers
186#define TRACE_INCLUDE_FILE syscalls_integers
187#include "instrumentation/syscalls/headers/syscalls_integers.h"
188#undef TRACE_INCLUDE_FILE
189#undef TRACE_SYSTEM
190#define TRACE_SYSTEM syscall_exit_pointers
191#define TRACE_INCLUDE_FILE syscalls_pointers
192#include "instrumentation/syscalls/headers/syscalls_pointers.h"
193#undef TRACE_INCLUDE_FILE
194#undef TRACE_SYSTEM
195#undef SC_TRACE_EVENT
196#undef SC_DECLARE_EVENT_CLASS_NOARGS
197#undef SC_DEFINE_EVENT_NOARGS
198#undef TP_PROBE_CB
199#undef _TRACE_SYSCALLS_integers_H
200#undef _TRACE_SYSCALLS_pointers_H
201
202
203/* Hijack probe callback for compat system call exit */
204#define TP_PROBE_CB(_template) &syscall_exit_probe
205#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
206 TRACE_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
207 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
208#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
209 DECLARE_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_struct), \
a93244f8
MD
210 PARAMS(_assign), PARAMS(_printk))
211#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358
MD
212 DEFINE_EVENT_NOARGS(compat_syscall_exit_##_template, \
213 compat_syscall_exit_##_name)
214#define TRACE_SYSTEM compat_syscall_exit_integers
215#define TRACE_INCLUDE_FILE compat_syscalls_integers
a93244f8 216#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
5b7ac358 217#undef TRACE_INCLUDE_FILE
a93244f8 218#undef TRACE_SYSTEM
5b7ac358
MD
219#define TRACE_SYSTEM compat_syscall_exit_pointers
220#define TRACE_INCLUDE_FILE compat_syscalls_pointers
a93244f8 221#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
5b7ac358 222#undef TRACE_INCLUDE_FILE
a93244f8
MD
223#undef TRACE_SYSTEM
224#undef SC_TRACE_EVENT
225#undef SC_DECLARE_EVENT_CLASS_NOARGS
226#undef SC_DEFINE_EVENT_NOARGS
227#undef TP_PROBE_CB
5b7ac358
MD
228#undef _TRACE_SYSCALLS_integers_H
229#undef _TRACE_SYSCALLS_pointers_H
230
fc4f7161 231#undef SC_EXIT
259b6cb3 232
2655f9ad 233#undef TP_MODULE_NOINIT
259b6cb3
MD
234#undef LTTNG_PACKAGE_BUILD
235#undef CREATE_TRACE_POINTS
236
a93244f8
MD
237struct trace_syscall_entry {
238 void *func;
239 const struct lttng_event_desc *desc;
240 const struct lttng_event_field *fields;
241 unsigned int nrargs;
242};
243
244#define CREATE_SYSCALL_TABLE
245
fc4f7161
MD
246#define SC_ENTER
247
248#undef sc_exit
249#define sc_exit(...)
250
259b6cb3 251#undef TRACE_SYSCALL_TABLE
f7bdf4db 252#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259b6cb3 253 [ _nr ] = { \
5b7ac358 254 .func = __event_probe__syscall_enter_##_template, \
259b6cb3 255 .nrargs = (_nrargs), \
5b7ac358
MD
256 .fields = __event_fields___syscall_enter_##_template, \
257 .desc = &__event_desc___syscall_enter_##_name, \
259b6cb3
MD
258 },
259
5b7ac358 260/* Syscall enter tracing table */
49c50022 261static const struct trace_syscall_entry sc_table[] = {
177b3692
MD
262#include "instrumentation/syscalls/headers/syscalls_integers.h"
263#include "instrumentation/syscalls/headers/syscalls_pointers.h"
259b6cb3
MD
264};
265
a93244f8
MD
266#undef TRACE_SYSCALL_TABLE
267#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
268 [ _nr ] = { \
5b7ac358 269 .func = __event_probe__compat_syscall_enter_##_template, \
a93244f8 270 .nrargs = (_nrargs), \
5b7ac358
MD
271 .fields = __event_fields___compat_syscall_enter_##_template, \
272 .desc = &__event_desc___compat_syscall_enter_##_name, \
a93244f8
MD
273 },
274
5b7ac358 275/* Compat syscall enter table */
a93244f8
MD
276const struct trace_syscall_entry compat_sc_table[] = {
277#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
278#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
279};
259b6cb3 280
fc4f7161
MD
281#undef SC_ENTER
282
283#define SC_EXIT
284
285#undef sc_exit
286#define sc_exit(...) __VA_ARGS__
287
5b7ac358
MD
288#undef TRACE_SYSCALL_TABLE
289#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
290 [ _nr ] = { \
291 .func = __event_probe__syscall_exit_##_template, \
292 .nrargs = (_nrargs), \
293 .fields = __event_fields___syscall_exit_##_template, \
294 .desc = &__event_desc___syscall_exit_##_name, \
295 },
296
297/* Syscall exit table */
298static const struct trace_syscall_entry sc_exit_table[] = {
299#include "instrumentation/syscalls/headers/syscalls_integers.h"
300#include "instrumentation/syscalls/headers/syscalls_pointers.h"
301};
302
303#undef TRACE_SYSCALL_TABLE
304#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
305 [ _nr ] = { \
306 .func = __event_probe__compat_syscall_exit_##_template, \
307 .nrargs = (_nrargs), \
308 .fields = __event_fields___compat_syscall_exit_##_template, \
309 .desc = &__event_desc___compat_syscall_exit_##_name, \
310 },
311
312/* Compat syscall exit table */
313const struct trace_syscall_entry compat_sc_exit_table[] = {
314#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
315#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
316};
317
fc4f7161
MD
318#undef SC_EXIT
319
a93244f8 320#undef CREATE_SYSCALL_TABLE
2faf7d1b 321
80f87dd2
MD
322struct lttng_syscall_filter {
323 DECLARE_BITMAP(sc, NR_syscalls);
324 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
325};
326
a90917c3 327static void syscall_entry_unknown(struct lttng_event *event,
f405cfce
MD
328 struct pt_regs *regs, unsigned int id)
329{
330 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
f405cfce 331
f405cfce 332 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
a93244f8 333 if (unlikely(is_compat_task()))
5b7ac358 334 __event_probe__compat_syscall_enter_unknown(event, id, args);
a93244f8 335 else
5b7ac358 336 __event_probe__syscall_enter_unknown(event, id, args);
f405cfce
MD
337}
338
2faf7d1b 339void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
259b6cb3 340{
a90917c3
MD
341 struct lttng_channel *chan = __data;
342 struct lttng_event *event, *unknown_event;
49c50022
MD
343 const struct trace_syscall_entry *table, *entry;
344 size_t table_len;
259b6cb3 345
b76dc1a0 346 if (unlikely(is_compat_task())) {
80f87dd2
MD
347 struct lttng_syscall_filter *filter;
348
349 filter = rcu_dereference(chan->sc_filter);
350 if (filter) {
351 if (id >= NR_compat_syscalls
352 || !test_bit(id, filter->sc_compat)) {
353 /* System call filtered out. */
354 return;
355 }
356 }
49c50022 357 table = compat_sc_table;
a93244f8 358 table_len = ARRAY_SIZE(compat_sc_table);
49c50022
MD
359 unknown_event = chan->sc_compat_unknown;
360 } else {
80f87dd2
MD
361 struct lttng_syscall_filter *filter;
362
363 filter = rcu_dereference(chan->sc_filter);
364 if (filter) {
365 if (id >= NR_syscalls
366 || !test_bit(id, filter->sc)) {
367 /* System call filtered out. */
368 return;
369 }
370 }
49c50022
MD
371 table = sc_table;
372 table_len = ARRAY_SIZE(sc_table);
373 unknown_event = chan->sc_unknown;
b76dc1a0 374 }
49c50022
MD
375 if (unlikely(id >= table_len)) {
376 syscall_entry_unknown(unknown_event, regs, id);
259b6cb3 377 return;
f405cfce 378 }
49c50022
MD
379 if (unlikely(is_compat_task()))
380 event = chan->compat_sc_table[id];
381 else
382 event = chan->sc_table[id];
f405cfce 383 if (unlikely(!event)) {
49c50022 384 syscall_entry_unknown(unknown_event, regs, id);
f405cfce
MD
385 return;
386 }
49c50022 387 entry = &table[id];
f405cfce 388 WARN_ON_ONCE(!entry);
259b6cb3
MD
389
390 switch (entry->nrargs) {
391 case 0:
392 {
393 void (*fptr)(void *__data) = entry->func;
394
395 fptr(event);
396 break;
397 }
398 case 1:
399 {
400 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
401 unsigned long args[1];
402
403 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
404 fptr(event, args[0]);
405 break;
406 }
407 case 2:
408 {
409 void (*fptr)(void *__data,
410 unsigned long arg0,
411 unsigned long arg1) = entry->func;
412 unsigned long args[2];
413
414 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
415 fptr(event, args[0], args[1]);
416 break;
417 }
418 case 3:
419 {
420 void (*fptr)(void *__data,
421 unsigned long arg0,
422 unsigned long arg1,
423 unsigned long arg2) = entry->func;
424 unsigned long args[3];
425
426 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
427 fptr(event, args[0], args[1], args[2]);
428 break;
429 }
430 case 4:
431 {
432 void (*fptr)(void *__data,
433 unsigned long arg0,
434 unsigned long arg1,
435 unsigned long arg2,
436 unsigned long arg3) = entry->func;
437 unsigned long args[4];
438
439 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
440 fptr(event, args[0], args[1], args[2], args[3]);
441 break;
442 }
443 case 5:
444 {
445 void (*fptr)(void *__data,
446 unsigned long arg0,
447 unsigned long arg1,
448 unsigned long arg2,
449 unsigned long arg3,
450 unsigned long arg4) = entry->func;
451 unsigned long args[5];
452
453 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
454 fptr(event, args[0], args[1], args[2], args[3], args[4]);
455 break;
456 }
457 case 6:
458 {
459 void (*fptr)(void *__data,
460 unsigned long arg0,
461 unsigned long arg1,
462 unsigned long arg2,
463 unsigned long arg3,
464 unsigned long arg4,
465 unsigned long arg5) = entry->func;
466 unsigned long args[6];
467
468 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
469 fptr(event, args[0], args[1], args[2],
470 args[3], args[4], args[5]);
471 break;
472 }
473 default:
474 break;
475 }
476}
477
5b7ac358
MD
478static void syscall_exit_unknown(struct lttng_event *event,
479 struct pt_regs *regs, unsigned int id, long ret)
480{
481 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
482
483 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
484 if (unlikely(is_compat_task()))
485 __event_probe__compat_syscall_exit_unknown(event, id, ret,
486 args);
487 else
488 __event_probe__syscall_exit_unknown(event, id, ret, args);
489}
490
491void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
492{
493 struct lttng_channel *chan = __data;
494 struct lttng_event *event, *unknown_event;
495 const struct trace_syscall_entry *table, *entry;
496 size_t table_len;
497 long id;
498
499 id = syscall_get_nr(current, regs);
500 if (unlikely(is_compat_task())) {
501 struct lttng_syscall_filter *filter;
502
503 filter = rcu_dereference(chan->sc_filter);
504 if (filter) {
505 if (id >= NR_compat_syscalls
506 || !test_bit(id, filter->sc_compat)) {
507 /* System call filtered out. */
508 return;
509 }
510 }
511 table = compat_sc_exit_table;
512 table_len = ARRAY_SIZE(compat_sc_exit_table);
513 unknown_event = chan->compat_sc_exit_unknown;
514 } else {
515 struct lttng_syscall_filter *filter;
516
517 filter = rcu_dereference(chan->sc_filter);
518 if (filter) {
519 if (id >= NR_syscalls
520 || !test_bit(id, filter->sc)) {
521 /* System call filtered out. */
522 return;
523 }
524 }
525 table = sc_exit_table;
526 table_len = ARRAY_SIZE(sc_exit_table);
527 unknown_event = chan->sc_exit_unknown;
528 }
529 if (unlikely(id >= table_len)) {
530 syscall_exit_unknown(unknown_event, regs, id, ret);
531 return;
532 }
533 if (unlikely(is_compat_task()))
534 event = chan->compat_sc_exit_table[id];
535 else
536 event = chan->sc_exit_table[id];
537 if (unlikely(!event)) {
538 syscall_exit_unknown(unknown_event, regs, id, ret);
539 return;
540 }
541 entry = &table[id];
542 WARN_ON_ONCE(!entry);
543
544 switch (entry->nrargs) {
545 case 0:
546 {
fc4f7161 547 void (*fptr)(void *__data, long ret) = entry->func;
5b7ac358 548
fc4f7161 549 fptr(event, ret);
5b7ac358
MD
550 break;
551 }
552 case 1:
553 {
554 void (*fptr)(void *__data,
fc4f7161 555 long ret,
5b7ac358
MD
556 unsigned long arg0) = entry->func;
557 unsigned long args[1];
558
559 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 560 fptr(event, ret, args[0]);
5b7ac358
MD
561 break;
562 }
563 case 2:
564 {
565 void (*fptr)(void *__data,
fc4f7161 566 long ret,
5b7ac358
MD
567 unsigned long arg0,
568 unsigned long arg1) = entry->func;
569 unsigned long args[2];
570
571 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 572 fptr(event, ret, args[0], args[1]);
5b7ac358
MD
573 break;
574 }
575 case 3:
576 {
577 void (*fptr)(void *__data,
fc4f7161 578 long ret,
5b7ac358
MD
579 unsigned long arg0,
580 unsigned long arg1,
581 unsigned long arg2) = entry->func;
582 unsigned long args[3];
583
584 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 585 fptr(event, ret, args[0], args[1], args[2]);
5b7ac358
MD
586 break;
587 }
588 case 4:
589 {
590 void (*fptr)(void *__data,
fc4f7161 591 long ret,
5b7ac358
MD
592 unsigned long arg0,
593 unsigned long arg1,
594 unsigned long arg2,
595 unsigned long arg3) = entry->func;
596 unsigned long args[4];
597
598 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 599 fptr(event, ret, args[0], args[1], args[2], args[3]);
5b7ac358
MD
600 break;
601 }
602 case 5:
603 {
604 void (*fptr)(void *__data,
fc4f7161 605 long ret,
5b7ac358
MD
606 unsigned long arg0,
607 unsigned long arg1,
608 unsigned long arg2,
609 unsigned long arg3,
610 unsigned long arg4) = entry->func;
611 unsigned long args[5];
612
613 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 614 fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
5b7ac358
MD
615 break;
616 }
617 case 6:
618 {
619 void (*fptr)(void *__data,
fc4f7161 620 long ret,
5b7ac358
MD
621 unsigned long arg0,
622 unsigned long arg1,
623 unsigned long arg2,
624 unsigned long arg3,
625 unsigned long arg4,
626 unsigned long arg5) = entry->func;
627 unsigned long args[6];
628
629 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 630 fptr(event, ret, args[0], args[1], args[2],
5b7ac358
MD
631 args[3], args[4], args[5]);
632 break;
633 }
634 default:
635 break;
636 }
637}
638
2a0c4816 639/* noinline to diminish caller stack size */
49c50022
MD
640static
641int fill_table(const struct trace_syscall_entry *table, size_t table_len,
5b7ac358
MD
642 struct lttng_event **chan_table, struct lttng_channel *chan,
643 void *filter, enum sc_type type)
259b6cb3 644{
2a0c4816 645 const struct lttng_event_desc *desc;
259b6cb3 646 unsigned int i;
49c50022
MD
647
648 /* Allocate events for each syscall, insert into table */
649 for (i = 0; i < table_len; i++) {
650 struct lttng_kernel_event ev;
2a0c4816 651 desc = table[i].desc;
49c50022
MD
652
653 if (!desc) {
654 /* Unknown syscall */
655 continue;
656 }
657 /*
658 * Skip those already populated by previous failed
659 * register for this channel.
660 */
661 if (chan_table[i])
662 continue;
663 memset(&ev, 0, sizeof(ev));
5b7ac358
MD
664 switch (type) {
665 case SC_TYPE_ENTRY:
666 strncpy(ev.name, SYSCALL_ENTRY_STR,
667 LTTNG_KERNEL_SYM_NAME_LEN);
668 break;
669 case SC_TYPE_EXIT:
670 strncpy(ev.name, SYSCALL_EXIT_STR,
671 LTTNG_KERNEL_SYM_NAME_LEN);
672 break;
673 case SC_TYPE_COMPAT_ENTRY:
674 strncpy(ev.name, COMPAT_SYSCALL_ENTRY_STR,
675 LTTNG_KERNEL_SYM_NAME_LEN);
676 break;
677 case SC_TYPE_COMPAT_EXIT:
678 strncpy(ev.name, COMPAT_SYSCALL_EXIT_STR,
679 LTTNG_KERNEL_SYM_NAME_LEN);
680 break;
681 default:
682 BUG_ON(1);
683 break;
684 }
685 strncat(ev.name, desc->name,
686 LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1);
f8695253 687 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
49c50022 688 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 689 chan_table[i] = lttng_event_create(chan, &ev, filter,
49c50022 690 desc);
abc0446a
MD
691 WARN_ON_ONCE(!chan_table[i]);
692 if (IS_ERR(chan_table[i])) {
49c50022
MD
693 /*
694 * If something goes wrong in event registration
695 * after the first one, we have no choice but to
696 * leave the previous events in there, until
697 * deleted by session teardown.
698 */
abc0446a 699 return PTR_ERR(chan_table[i]);
49c50022
MD
700 }
701 }
702 return 0;
703}
704
a90917c3 705int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
49c50022 706{
2a0c4816 707 struct lttng_kernel_event ev;
259b6cb3
MD
708 int ret;
709
710 wrapper_vmalloc_sync_all();
259b6cb3
MD
711
712 if (!chan->sc_table) {
713 /* create syscall table mapping syscall to events */
a90917c3 714 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
259b6cb3
MD
715 * ARRAY_SIZE(sc_table), GFP_KERNEL);
716 if (!chan->sc_table)
717 return -ENOMEM;
718 }
5b7ac358
MD
719 if (!chan->sc_exit_table) {
720 /* create syscall table mapping syscall to events */
721 chan->sc_exit_table = kzalloc(sizeof(struct lttng_event *)
722 * ARRAY_SIZE(sc_exit_table), GFP_KERNEL);
723 if (!chan->sc_exit_table)
724 return -ENOMEM;
725 }
726
259b6cb3 727
49c50022
MD
728#ifdef CONFIG_COMPAT
729 if (!chan->compat_sc_table) {
730 /* create syscall table mapping compat syscall to events */
a90917c3 731 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
a93244f8 732 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
49c50022
MD
733 if (!chan->compat_sc_table)
734 return -ENOMEM;
735 }
5b7ac358
MD
736
737 if (!chan->compat_sc_exit_table) {
738 /* create syscall table mapping compat syscall to events */
739 chan->compat_sc_exit_table = kzalloc(sizeof(struct lttng_event *)
740 * ARRAY_SIZE(compat_sc_exit_table), GFP_KERNEL);
741 if (!chan->compat_sc_exit_table)
742 return -ENOMEM;
743 }
49c50022 744#endif
f405cfce 745 if (!chan->sc_unknown) {
f405cfce 746 const struct lttng_event_desc *desc =
5b7ac358 747 &__event_desc___syscall_enter_unknown;
2f804c0a 748
f405cfce 749 memset(&ev, 0, sizeof(ev));
f8695253
MD
750 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
751 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
f405cfce 752 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 753 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
f405cfce 754 desc);
abc0446a
MD
755 WARN_ON_ONCE(!chan->sc_unknown);
756 if (IS_ERR(chan->sc_unknown)) {
757 return PTR_ERR(chan->sc_unknown);
f405cfce
MD
758 }
759 }
760
b76dc1a0 761 if (!chan->sc_compat_unknown) {
b76dc1a0 762 const struct lttng_event_desc *desc =
5b7ac358 763 &__event_desc___compat_syscall_enter_unknown;
b76dc1a0
MD
764
765 memset(&ev, 0, sizeof(ev));
f8695253
MD
766 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
767 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
b76dc1a0 768 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 769 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
b76dc1a0 770 desc);
abc0446a
MD
771 WARN_ON_ONCE(!chan->sc_unknown);
772 if (IS_ERR(chan->sc_compat_unknown)) {
773 return PTR_ERR(chan->sc_compat_unknown);
b76dc1a0
MD
774 }
775 }
776
5b7ac358 777 if (!chan->compat_sc_exit_unknown) {
2f804c0a 778 const struct lttng_event_desc *desc =
5b7ac358 779 &__event_desc___compat_syscall_exit_unknown;
2f804c0a
MD
780
781 memset(&ev, 0, sizeof(ev));
f8695253
MD
782 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
783 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
2f804c0a 784 ev.instrumentation = LTTNG_KERNEL_NOOP;
5b7ac358
MD
785 chan->compat_sc_exit_unknown = lttng_event_create(chan, &ev,
786 filter, desc);
787 WARN_ON_ONCE(!chan->compat_sc_exit_unknown);
788 if (IS_ERR(chan->compat_sc_exit_unknown)) {
789 return PTR_ERR(chan->compat_sc_exit_unknown);
790 }
791 }
792
793 if (!chan->sc_exit_unknown) {
794 const struct lttng_event_desc *desc =
795 &__event_desc___syscall_exit_unknown;
796
797 memset(&ev, 0, sizeof(ev));
798 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
799 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
800 ev.instrumentation = LTTNG_KERNEL_NOOP;
801 chan->sc_exit_unknown = lttng_event_create(chan, &ev, filter,
2f804c0a 802 desc);
5b7ac358
MD
803 WARN_ON_ONCE(!chan->sc_exit_unknown);
804 if (IS_ERR(chan->sc_exit_unknown)) {
805 return PTR_ERR(chan->sc_exit_unknown);
2f804c0a
MD
806 }
807 }
808
49c50022 809 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
5b7ac358
MD
810 chan->sc_table, chan, filter, SC_TYPE_ENTRY);
811 if (ret)
812 return ret;
813 ret = fill_table(sc_exit_table, ARRAY_SIZE(sc_exit_table),
814 chan->sc_exit_table, chan, filter, SC_TYPE_EXIT);
49c50022
MD
815 if (ret)
816 return ret;
5b7ac358 817
49c50022 818#ifdef CONFIG_COMPAT
a93244f8 819 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
5b7ac358
MD
820 chan->compat_sc_table, chan, filter,
821 SC_TYPE_COMPAT_ENTRY);
822 if (ret)
823 return ret;
824 ret = fill_table(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
825 chan->compat_sc_exit_table, chan, filter,
826 SC_TYPE_COMPAT_EXIT);
49c50022
MD
827 if (ret)
828 return ret;
829#endif
80f87dd2
MD
830 if (!chan->sys_enter_registered) {
831 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
832 (void *) syscall_entry_probe, chan);
833 if (ret)
834 return ret;
835 chan->sys_enter_registered = 1;
836 }
63728b02
MD
837 /*
838 * We change the name of sys_exit tracepoint due to namespace
839 * conflict with sys_exit syscall entry.
840 */
80f87dd2
MD
841 if (!chan->sys_exit_registered) {
842 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
5b7ac358 843 (void *) syscall_exit_probe, chan);
80f87dd2
MD
844 if (ret) {
845 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
846 (void *) syscall_entry_probe, chan));
847 return ret;
848 }
849 chan->sys_exit_registered = 1;
63728b02 850 }
259b6cb3
MD
851 return ret;
852}
853
854/*
855 * Only called at session destruction.
856 */
a90917c3 857int lttng_syscalls_unregister(struct lttng_channel *chan)
259b6cb3
MD
858{
859 int ret;
860
861 if (!chan->sc_table)
862 return 0;
80f87dd2
MD
863 if (chan->sys_enter_registered) {
864 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
5b7ac358 865 (void *) syscall_exit_probe, chan);
80f87dd2
MD
866 if (ret)
867 return ret;
868 chan->sys_enter_registered = 0;
869 }
870 if (chan->sys_exit_registered) {
871 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
872 (void *) syscall_entry_probe, chan);
873 if (ret)
874 return ret;
875 chan->sys_exit_registered = 0;
876 }
a90917c3 877 /* lttng_event destroy will be performed by lttng_session_destroy() */
259b6cb3 878 kfree(chan->sc_table);
5b7ac358 879 kfree(chan->sc_exit_table);
49c50022
MD
880#ifdef CONFIG_COMPAT
881 kfree(chan->compat_sc_table);
5b7ac358 882 kfree(chan->compat_sc_exit_table);
49c50022 883#endif
80f87dd2
MD
884 kfree(chan->sc_filter);
885 return 0;
886}
887
888static
889int get_syscall_nr(const char *syscall_name)
890{
891 int syscall_nr = -1;
892 int i;
893
894 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
895 const struct trace_syscall_entry *entry;
5b7ac358 896 const char *it_name;
80f87dd2
MD
897
898 entry = &sc_table[i];
899 if (!entry->desc)
900 continue;
5b7ac358
MD
901 it_name = entry->desc->name;
902 it_name += strlen(SYSCALL_ENTRY_STR);
903 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
904 syscall_nr = i;
905 break;
906 }
907 }
908 return syscall_nr;
909}
910
911static
912int get_compat_syscall_nr(const char *syscall_name)
913{
914 int syscall_nr = -1;
915 int i;
916
917 for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++) {
918 const struct trace_syscall_entry *entry;
5b7ac358 919 const char *it_name;
80f87dd2
MD
920
921 entry = &compat_sc_table[i];
922 if (!entry->desc)
923 continue;
5b7ac358
MD
924 it_name = entry->desc->name;
925 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
926 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
927 syscall_nr = i;
928 break;
929 }
930 }
931 return syscall_nr;
932}
933
934int lttng_syscall_filter_enable(struct lttng_channel *chan,
935 const char *name)
936{
937 int syscall_nr, compat_syscall_nr, ret;
938 struct lttng_syscall_filter *filter;
939
940 WARN_ON_ONCE(!chan->sc_table);
941
942 if (!name) {
943 /* Enable all system calls by removing filter */
944 if (chan->sc_filter) {
945 filter = chan->sc_filter;
946 rcu_assign_pointer(chan->sc_filter, NULL);
947 synchronize_trace();
948 kfree(filter);
949 }
950 chan->syscall_all = 1;
951 return 0;
952 }
953
954 if (!chan->sc_filter) {
955 if (chan->syscall_all) {
956 /*
957 * All syscalls are already enabled.
958 */
959 return -EEXIST;
960 }
961 filter = kzalloc(sizeof(struct lttng_syscall_filter),
962 GFP_KERNEL);
963 if (!filter)
964 return -ENOMEM;
965 } else {
966 filter = chan->sc_filter;
967 }
968 syscall_nr = get_syscall_nr(name);
969 compat_syscall_nr = get_compat_syscall_nr(name);
970 if (syscall_nr < 0 && compat_syscall_nr < 0) {
971 ret = -ENOENT;
972 goto error;
973 }
974 if (syscall_nr >= 0) {
975 if (test_bit(syscall_nr, filter->sc)) {
976 ret = -EEXIST;
977 goto error;
978 }
979 bitmap_set(filter->sc, syscall_nr, 1);
980 }
981 if (compat_syscall_nr >= 0) {
982 if (test_bit(compat_syscall_nr, filter->sc_compat)) {
983 ret = -EEXIST;
984 goto error;
985 }
986 bitmap_set(filter->sc_compat, compat_syscall_nr, 1);
987 }
988 if (!chan->sc_filter)
989 rcu_assign_pointer(chan->sc_filter, filter);
990 return 0;
991
992error:
993 if (!chan->sc_filter)
994 kfree(filter);
995 return ret;
996}
997
998int lttng_syscall_filter_disable(struct lttng_channel *chan,
999 const char *name)
1000{
1001 int syscall_nr, compat_syscall_nr, ret;
1002 struct lttng_syscall_filter *filter;
1003
1004 WARN_ON_ONCE(!chan->sc_table);
1005
1006 if (!chan->sc_filter) {
1007 filter = kzalloc(sizeof(struct lttng_syscall_filter),
1008 GFP_KERNEL);
1009 if (!filter)
1010 return -ENOMEM;
1011 /* Trace all system calls, then apply disable. */
1012 bitmap_set(filter->sc, 0, NR_syscalls);
1013 bitmap_set(filter->sc_compat, 0, NR_compat_syscalls);
1014 } else {
1015 filter = chan->sc_filter;
1016 }
1017
1018 syscall_nr = get_syscall_nr(name);
1019 compat_syscall_nr = get_compat_syscall_nr(name);
1020 if (syscall_nr < 0 && compat_syscall_nr < 0) {
1021 ret = -ENOENT;
1022 goto error;
1023 }
1024 if (syscall_nr >= 0) {
1025 if (!test_bit(syscall_nr, chan->sc_filter->sc)) {
1026 ret = -EEXIST;
1027 goto error;
1028 }
1029 bitmap_clear(chan->sc_filter->sc, syscall_nr, 1);
1030 }
1031 if (compat_syscall_nr >= 0) {
1032 if (!test_bit(compat_syscall_nr, chan->sc_filter->sc_compat)) {
1033 ret = -EEXIST;
1034 goto error;
1035 }
1036 bitmap_clear(chan->sc_filter->sc_compat, compat_syscall_nr, 1);
1037 }
1038 if (!chan->sc_filter)
1039 rcu_assign_pointer(chan->sc_filter, filter);
1040 chan->syscall_all = 0;
259b6cb3 1041 return 0;
80f87dd2
MD
1042
1043error:
1044 if (!chan->sc_filter)
1045 kfree(filter);
1046 return ret;
259b6cb3 1047}
This page took 0.072902 seconds and 4 git commands to generate.