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