Extract system call exit return value
[lttng-modules.git] / lttng-syscalls.c
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
40 enum 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
52 static
53 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
54 static
55 void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
56
57 /*
58 * Forward declarations for old kernels.
59 */
60 struct mmsghdr;
61 struct rlimit64;
62 struct oldold_utsname;
63 struct old_utsname;
64 struct sel_arg_struct;
65 struct 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_PROTO
98 #define SC_EXIT_PROTO(...)
99 #undef SC_EXIT_ARGS
100 #define SC_EXIT_ARGS(...)
101 #undef sc_exit
102 #define sc_exit(...)
103
104 /* Hijack probe callback for system call enter */
105 #undef TP_PROBE_CB
106 #define TP_PROBE_CB(_template) &syscall_entry_probe
107 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
108 TRACE_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
109 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
110 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
111 DECLARE_EVENT_CLASS_NOARGS(syscall_enter_##_name, PARAMS(_struct), PARAMS(_assign),\
112 PARAMS(_printk))
113 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
114 DEFINE_EVENT_NOARGS(syscall_enter_##_template, syscall_enter_##_name)
115 #undef TRACE_SYSTEM
116 #define TRACE_SYSTEM syscall_enter_integers
117 #define TRACE_INCLUDE_FILE syscalls_integers
118 #include "instrumentation/syscalls/headers/syscalls_integers.h"
119 #undef TRACE_INCLUDE_FILE
120 #undef TRACE_SYSTEM
121 #define TRACE_SYSTEM syscall_enter_pointers
122 #define TRACE_INCLUDE_FILE syscalls_pointers
123 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
124 #undef TRACE_INCLUDE_FILE
125 #undef TRACE_SYSTEM
126 #undef SC_TRACE_EVENT
127 #undef SC_DECLARE_EVENT_CLASS_NOARGS
128 #undef SC_DEFINE_EVENT_NOARGS
129 #undef TP_PROBE_CB
130 #undef _TRACE_SYSCALLS_integers_H
131 #undef _TRACE_SYSCALLS_pointers_H
132
133
134 /* Hijack probe callback for compat system call enter */
135 #define TP_PROBE_CB(_template) &syscall_entry_probe
136 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
137 TRACE_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
138 PARAMS(_struct), PARAMS(_assign), \
139 PARAMS(_printk))
140 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
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
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__
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), \
210 PARAMS(_assign), PARAMS(_printk))
211 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
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
216 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
217 #undef TRACE_INCLUDE_FILE
218 #undef TRACE_SYSTEM
219 #define TRACE_SYSTEM compat_syscall_exit_pointers
220 #define TRACE_INCLUDE_FILE compat_syscalls_pointers
221 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
222 #undef TRACE_INCLUDE_FILE
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
228 #undef _TRACE_SYSCALLS_integers_H
229 #undef _TRACE_SYSCALLS_pointers_H
230
231 #undef SC_EXIT
232
233 #undef TP_MODULE_NOINIT
234 #undef LTTNG_PACKAGE_BUILD
235 #undef CREATE_TRACE_POINTS
236
237 struct 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
246 #define SC_ENTER
247
248 #undef sc_exit
249 #define sc_exit(...)
250
251 #undef TRACE_SYSCALL_TABLE
252 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
253 [ _nr ] = { \
254 .func = __event_probe__syscall_enter_##_template, \
255 .nrargs = (_nrargs), \
256 .fields = __event_fields___syscall_enter_##_template, \
257 .desc = &__event_desc___syscall_enter_##_name, \
258 },
259
260 /* Syscall enter tracing table */
261 static const struct trace_syscall_entry sc_table[] = {
262 #include "instrumentation/syscalls/headers/syscalls_integers.h"
263 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
264 };
265
266 #undef TRACE_SYSCALL_TABLE
267 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
268 [ _nr ] = { \
269 .func = __event_probe__compat_syscall_enter_##_template, \
270 .nrargs = (_nrargs), \
271 .fields = __event_fields___compat_syscall_enter_##_template, \
272 .desc = &__event_desc___compat_syscall_enter_##_name, \
273 },
274
275 /* Compat syscall enter table */
276 const 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 };
280
281 #undef SC_ENTER
282
283 #define SC_EXIT
284
285 #undef sc_exit
286 #define sc_exit(...) __VA_ARGS__
287
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 */
298 static 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 */
313 const 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
318 #undef SC_EXIT
319
320 #undef CREATE_SYSCALL_TABLE
321
322 struct lttng_syscall_filter {
323 DECLARE_BITMAP(sc, NR_syscalls);
324 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
325 };
326
327 static void syscall_entry_unknown(struct lttng_event *event,
328 struct pt_regs *regs, unsigned int id)
329 {
330 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
331
332 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
333 if (unlikely(is_compat_task()))
334 __event_probe__compat_syscall_enter_unknown(event, id, args);
335 else
336 __event_probe__syscall_enter_unknown(event, id, args);
337 }
338
339 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
340 {
341 struct lttng_channel *chan = __data;
342 struct lttng_event *event, *unknown_event;
343 const struct trace_syscall_entry *table, *entry;
344 size_t table_len;
345
346 if (unlikely(is_compat_task())) {
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 }
357 table = compat_sc_table;
358 table_len = ARRAY_SIZE(compat_sc_table);
359 unknown_event = chan->sc_compat_unknown;
360 } else {
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 }
371 table = sc_table;
372 table_len = ARRAY_SIZE(sc_table);
373 unknown_event = chan->sc_unknown;
374 }
375 if (unlikely(id >= table_len)) {
376 syscall_entry_unknown(unknown_event, regs, id);
377 return;
378 }
379 if (unlikely(is_compat_task()))
380 event = chan->compat_sc_table[id];
381 else
382 event = chan->sc_table[id];
383 if (unlikely(!event)) {
384 syscall_entry_unknown(unknown_event, regs, id);
385 return;
386 }
387 entry = &table[id];
388 WARN_ON_ONCE(!entry);
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
478 static 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
491 void 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 {
547 void (*fptr)(void *__data, long ret) = entry->func;
548
549 fptr(event, ret);
550 break;
551 }
552 case 1:
553 {
554 void (*fptr)(void *__data,
555 long ret,
556 unsigned long arg0) = entry->func;
557 unsigned long args[1];
558
559 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
560 fptr(event, ret, args[0]);
561 break;
562 }
563 case 2:
564 {
565 void (*fptr)(void *__data,
566 long ret,
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);
572 fptr(event, ret, args[0], args[1]);
573 break;
574 }
575 case 3:
576 {
577 void (*fptr)(void *__data,
578 long ret,
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);
585 fptr(event, ret, args[0], args[1], args[2]);
586 break;
587 }
588 case 4:
589 {
590 void (*fptr)(void *__data,
591 long ret,
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);
599 fptr(event, ret, args[0], args[1], args[2], args[3]);
600 break;
601 }
602 case 5:
603 {
604 void (*fptr)(void *__data,
605 long ret,
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);
614 fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
615 break;
616 }
617 case 6:
618 {
619 void (*fptr)(void *__data,
620 long ret,
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);
630 fptr(event, ret, args[0], args[1], args[2],
631 args[3], args[4], args[5]);
632 break;
633 }
634 default:
635 break;
636 }
637 }
638
639 /* noinline to diminish caller stack size */
640 static
641 int fill_table(const struct trace_syscall_entry *table, size_t table_len,
642 struct lttng_event **chan_table, struct lttng_channel *chan,
643 void *filter, enum sc_type type)
644 {
645 const struct lttng_event_desc *desc;
646 unsigned int i;
647
648 /* Allocate events for each syscall, insert into table */
649 for (i = 0; i < table_len; i++) {
650 struct lttng_kernel_event ev;
651 desc = table[i].desc;
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));
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);
687 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
688 ev.instrumentation = LTTNG_KERNEL_NOOP;
689 chan_table[i] = lttng_event_create(chan, &ev, filter,
690 desc);
691 WARN_ON_ONCE(!chan_table[i]);
692 if (IS_ERR(chan_table[i])) {
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 */
699 return PTR_ERR(chan_table[i]);
700 }
701 }
702 return 0;
703 }
704
705 int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
706 {
707 struct lttng_kernel_event ev;
708 int ret;
709
710 wrapper_vmalloc_sync_all();
711
712 if (!chan->sc_table) {
713 /* create syscall table mapping syscall to events */
714 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
715 * ARRAY_SIZE(sc_table), GFP_KERNEL);
716 if (!chan->sc_table)
717 return -ENOMEM;
718 }
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
727
728 #ifdef CONFIG_COMPAT
729 if (!chan->compat_sc_table) {
730 /* create syscall table mapping compat syscall to events */
731 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
732 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
733 if (!chan->compat_sc_table)
734 return -ENOMEM;
735 }
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 }
744 #endif
745 if (!chan->sc_unknown) {
746 const struct lttng_event_desc *desc =
747 &__event_desc___syscall_enter_unknown;
748
749 memset(&ev, 0, sizeof(ev));
750 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
751 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
752 ev.instrumentation = LTTNG_KERNEL_NOOP;
753 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
754 desc);
755 WARN_ON_ONCE(!chan->sc_unknown);
756 if (IS_ERR(chan->sc_unknown)) {
757 return PTR_ERR(chan->sc_unknown);
758 }
759 }
760
761 if (!chan->sc_compat_unknown) {
762 const struct lttng_event_desc *desc =
763 &__event_desc___compat_syscall_enter_unknown;
764
765 memset(&ev, 0, sizeof(ev));
766 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
767 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
768 ev.instrumentation = LTTNG_KERNEL_NOOP;
769 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
770 desc);
771 WARN_ON_ONCE(!chan->sc_unknown);
772 if (IS_ERR(chan->sc_compat_unknown)) {
773 return PTR_ERR(chan->sc_compat_unknown);
774 }
775 }
776
777 if (!chan->compat_sc_exit_unknown) {
778 const struct lttng_event_desc *desc =
779 &__event_desc___compat_syscall_exit_unknown;
780
781 memset(&ev, 0, sizeof(ev));
782 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
783 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
784 ev.instrumentation = LTTNG_KERNEL_NOOP;
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,
802 desc);
803 WARN_ON_ONCE(!chan->sc_exit_unknown);
804 if (IS_ERR(chan->sc_exit_unknown)) {
805 return PTR_ERR(chan->sc_exit_unknown);
806 }
807 }
808
809 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
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);
815 if (ret)
816 return ret;
817
818 #ifdef CONFIG_COMPAT
819 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
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);
827 if (ret)
828 return ret;
829 #endif
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 }
837 /*
838 * We change the name of sys_exit tracepoint due to namespace
839 * conflict with sys_exit syscall entry.
840 */
841 if (!chan->sys_exit_registered) {
842 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
843 (void *) syscall_exit_probe, chan);
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;
850 }
851 return ret;
852 }
853
854 /*
855 * Only called at session destruction.
856 */
857 int lttng_syscalls_unregister(struct lttng_channel *chan)
858 {
859 int ret;
860
861 if (!chan->sc_table)
862 return 0;
863 if (chan->sys_enter_registered) {
864 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
865 (void *) syscall_exit_probe, chan);
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 }
877 /* lttng_event destroy will be performed by lttng_session_destroy() */
878 kfree(chan->sc_table);
879 kfree(chan->sc_exit_table);
880 #ifdef CONFIG_COMPAT
881 kfree(chan->compat_sc_table);
882 kfree(chan->compat_sc_exit_table);
883 #endif
884 kfree(chan->sc_filter);
885 return 0;
886 }
887
888 static
889 int 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;
896 const char *it_name;
897
898 entry = &sc_table[i];
899 if (!entry->desc)
900 continue;
901 it_name = entry->desc->name;
902 it_name += strlen(SYSCALL_ENTRY_STR);
903 if (!strcmp(syscall_name, it_name)) {
904 syscall_nr = i;
905 break;
906 }
907 }
908 return syscall_nr;
909 }
910
911 static
912 int 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;
919 const char *it_name;
920
921 entry = &compat_sc_table[i];
922 if (!entry->desc)
923 continue;
924 it_name = entry->desc->name;
925 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
926 if (!strcmp(syscall_name, it_name)) {
927 syscall_nr = i;
928 break;
929 }
930 }
931 return syscall_nr;
932 }
933
934 int 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
992 error:
993 if (!chan->sc_filter)
994 kfree(filter);
995 return ret;
996 }
997
998 int 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;
1041 return 0;
1042
1043 error:
1044 if (!chan->sc_filter)
1045 kfree(filter);
1046 return ret;
1047 }
This page took 0.05762 seconds and 5 git commands to generate.