System call inout/output arg processing
[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
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
241 struct 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 */
265 static 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 */
280 const 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 */
302 static 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 */
317 const 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
326 struct lttng_syscall_filter {
327 DECLARE_BITMAP(sc, NR_syscalls);
328 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
329 };
330
331 static 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
343 void 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
482 static 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
495 void 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 */
644 static
645 int 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
709 int 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 */
861 int 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
892 static
893 int 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
915 static
916 int 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
938 int 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
996 error:
997 if (!chan->sc_filter)
998 kfree(filter);
999 return ret;
1000 }
1001
1002 int 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
1047 error:
1048 if (!chan->sc_filter)
1049 kfree(filter);
1050 return ret;
1051 }
This page took 0.050721 seconds and 5 git commands to generate.