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