syscall: extract pipe and pipe2 output args
[lttng-modules.git] / lttng-syscalls.c
CommitLineData
259b6cb3
MD
1/*
2 * lttng-syscalls.c
3 *
2faf7d1b 4 * LTTng syscall probes.
259b6cb3 5 *
886d51a3
MD
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
259b6cb3
MD
21 */
22
23#include <linux/module.h>
24#include <linux/slab.h>
6333ace3 25#include <linux/compat.h>
abc0446a 26#include <linux/err.h>
80f87dd2 27#include <linux/bitmap.h>
259b6cb3
MD
28#include <asm/ptrace.h>
29#include <asm/syscall.h>
30
3a523f5b 31#include "wrapper/tracepoint.h"
a90917c3 32#include "lttng-events.h"
259b6cb3 33
6333ace3 34#ifndef CONFIG_COMPAT
bfa949bf
MD
35# ifndef is_compat_task
36# define is_compat_task() (0)
37# endif
6333ace3
MD
38#endif
39
5b7ac358
MD
40enum sc_type {
41 SC_TYPE_ENTRY,
42 SC_TYPE_EXIT,
43 SC_TYPE_COMPAT_ENTRY,
44 SC_TYPE_COMPAT_EXIT,
45};
46
47#define SYSCALL_ENTRY_STR "syscall_entry_"
48#define COMPAT_SYSCALL_ENTRY_STR "compat_syscall_entry_"
49#define SYSCALL_EXIT_STR "syscall_exit_"
50#define COMPAT_SYSCALL_EXIT_STR "compat_syscall_exit_"
51
a93244f8 52static
2faf7d1b 53void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
5b7ac358
MD
54static
55void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
259b6cb3 56
3a523f5b
MD
57/*
58 * Forward declarations for old kernels.
59 */
60struct mmsghdr;
61struct rlimit64;
62struct oldold_utsname;
63struct old_utsname;
64struct sel_arg_struct;
65struct mmap_arg_struct;
66
80f87dd2
MD
67#ifdef IA32_NR_syscalls
68#define NR_compat_syscalls IA32_NR_syscalls
69#else
70#define NR_compat_syscalls NR_syscalls
71#endif
72
f7bdf4db
MD
73/*
74 * Take care of NOARGS not supported by mainline.
75 */
76#define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
77#define DEFINE_EVENT_NOARGS(template, name)
78#define TRACE_EVENT_NOARGS(name, struct, assign, print)
79
259b6cb3
MD
80/*
81 * Create LTTng tracepoint probes.
82 */
83#define LTTNG_PACKAGE_BUILD
84#define CREATE_TRACE_POINTS
2655f9ad 85#define TP_MODULE_NOINIT
2f804c0a 86#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
259b6cb3 87
a93244f8
MD
88#define PARAMS(args...) args
89
5b7ac358
MD
90/* Handle unknown syscalls */
91#define TRACE_SYSTEM syscalls_unknown
92#include "instrumentation/syscalls/headers/syscalls_unknown.h"
93#undef TRACE_SYSTEM
94
fc4f7161
MD
95#define SC_ENTER
96
fc4f7161
MD
97#undef sc_exit
98#define sc_exit(...)
b75d00c4
MD
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__
5b7ac358
MD
105
106/* Hijack probe callback for system call enter */
a93244f8 107#undef TP_PROBE_CB
259b6cb3 108#define TP_PROBE_CB(_template) &syscall_entry_probe
a93244f8 109#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 110 TRACE_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
a93244f8
MD
111 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
112#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358 113 DECLARE_EVENT_CLASS_NOARGS(syscall_enter_##_name, PARAMS(_struct), PARAMS(_assign),\
a93244f8
MD
114 PARAMS(_printk))
115#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358 116 DEFINE_EVENT_NOARGS(syscall_enter_##_template, syscall_enter_##_name)
a93244f8 117#undef TRACE_SYSTEM
5b7ac358
MD
118#define TRACE_SYSTEM syscall_enter_integers
119#define TRACE_INCLUDE_FILE syscalls_integers
177b3692 120#include "instrumentation/syscalls/headers/syscalls_integers.h"
5b7ac358 121#undef TRACE_INCLUDE_FILE
a93244f8 122#undef TRACE_SYSTEM
5b7ac358
MD
123#define TRACE_SYSTEM syscall_enter_pointers
124#define TRACE_INCLUDE_FILE syscalls_pointers
177b3692 125#include "instrumentation/syscalls/headers/syscalls_pointers.h"
5b7ac358 126#undef TRACE_INCLUDE_FILE
a93244f8
MD
127#undef TRACE_SYSTEM
128#undef SC_TRACE_EVENT
129#undef SC_DECLARE_EVENT_CLASS_NOARGS
130#undef SC_DEFINE_EVENT_NOARGS
5b7ac358 131#undef TP_PROBE_CB
a93244f8
MD
132#undef _TRACE_SYSCALLS_integers_H
133#undef _TRACE_SYSCALLS_pointers_H
134
5b7ac358
MD
135
136/* Hijack probe callback for compat system call enter */
a93244f8
MD
137#define TP_PROBE_CB(_template) &syscall_entry_probe
138#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 139 TRACE_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
a93244f8
MD
140 PARAMS(_struct), PARAMS(_assign), \
141 PARAMS(_printk))
142#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358
MD
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
fc4f7161
MD
165#undef SC_ENTER
166
167#define SC_EXIT
168
fc4f7161
MD
169#undef sc_exit
170#define sc_exit(...) __VA_ARGS__
b75d00c4
MD
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__
5b7ac358
MD
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), \
a93244f8
MD
214 PARAMS(_assign), PARAMS(_printk))
215#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358
MD
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
a93244f8 220#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
5b7ac358 221#undef TRACE_INCLUDE_FILE
a93244f8 222#undef TRACE_SYSTEM
5b7ac358
MD
223#define TRACE_SYSTEM compat_syscall_exit_pointers
224#define TRACE_INCLUDE_FILE compat_syscalls_pointers
a93244f8 225#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
5b7ac358 226#undef TRACE_INCLUDE_FILE
a93244f8
MD
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
5b7ac358
MD
232#undef _TRACE_SYSCALLS_integers_H
233#undef _TRACE_SYSCALLS_pointers_H
234
fc4f7161 235#undef SC_EXIT
259b6cb3 236
2655f9ad 237#undef TP_MODULE_NOINIT
259b6cb3
MD
238#undef LTTNG_PACKAGE_BUILD
239#undef CREATE_TRACE_POINTS
240
a93244f8
MD
241struct trace_syscall_entry {
242 void *func;
243 const struct lttng_event_desc *desc;
244 const struct lttng_event_field *fields;
245 unsigned int nrargs;
246};
247
248#define CREATE_SYSCALL_TABLE
249
fc4f7161
MD
250#define SC_ENTER
251
252#undef sc_exit
253#define sc_exit(...)
254
259b6cb3 255#undef TRACE_SYSCALL_TABLE
f7bdf4db 256#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259b6cb3 257 [ _nr ] = { \
5b7ac358 258 .func = __event_probe__syscall_enter_##_template, \
259b6cb3 259 .nrargs = (_nrargs), \
5b7ac358
MD
260 .fields = __event_fields___syscall_enter_##_template, \
261 .desc = &__event_desc___syscall_enter_##_name, \
259b6cb3
MD
262 },
263
5b7ac358 264/* Syscall enter tracing table */
49c50022 265static const struct trace_syscall_entry sc_table[] = {
177b3692
MD
266#include "instrumentation/syscalls/headers/syscalls_integers.h"
267#include "instrumentation/syscalls/headers/syscalls_pointers.h"
259b6cb3
MD
268};
269
a93244f8
MD
270#undef TRACE_SYSCALL_TABLE
271#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
272 [ _nr ] = { \
5b7ac358 273 .func = __event_probe__compat_syscall_enter_##_template, \
a93244f8 274 .nrargs = (_nrargs), \
5b7ac358
MD
275 .fields = __event_fields___compat_syscall_enter_##_template, \
276 .desc = &__event_desc___compat_syscall_enter_##_name, \
a93244f8
MD
277 },
278
5b7ac358 279/* Compat syscall enter table */
a93244f8
MD
280const struct trace_syscall_entry compat_sc_table[] = {
281#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
282#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
283};
259b6cb3 284
fc4f7161
MD
285#undef SC_ENTER
286
287#define SC_EXIT
288
289#undef sc_exit
290#define sc_exit(...) __VA_ARGS__
291
5b7ac358
MD
292#undef TRACE_SYSCALL_TABLE
293#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
294 [ _nr ] = { \
295 .func = __event_probe__syscall_exit_##_template, \
296 .nrargs = (_nrargs), \
297 .fields = __event_fields___syscall_exit_##_template, \
298 .desc = &__event_desc___syscall_exit_##_name, \
299 },
300
301/* Syscall exit table */
302static const struct trace_syscall_entry sc_exit_table[] = {
303#include "instrumentation/syscalls/headers/syscalls_integers.h"
304#include "instrumentation/syscalls/headers/syscalls_pointers.h"
305};
306
307#undef TRACE_SYSCALL_TABLE
308#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
309 [ _nr ] = { \
310 .func = __event_probe__compat_syscall_exit_##_template, \
311 .nrargs = (_nrargs), \
312 .fields = __event_fields___compat_syscall_exit_##_template, \
313 .desc = &__event_desc___compat_syscall_exit_##_name, \
314 },
315
316/* Compat syscall exit table */
317const struct trace_syscall_entry compat_sc_exit_table[] = {
318#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
319#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
320};
321
fc4f7161
MD
322#undef SC_EXIT
323
a93244f8 324#undef CREATE_SYSCALL_TABLE
2faf7d1b 325
80f87dd2
MD
326struct lttng_syscall_filter {
327 DECLARE_BITMAP(sc, NR_syscalls);
328 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
329};
330
a90917c3 331static void syscall_entry_unknown(struct lttng_event *event,
f405cfce
MD
332 struct pt_regs *regs, unsigned int id)
333{
334 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
f405cfce 335
f405cfce 336 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
a93244f8 337 if (unlikely(is_compat_task()))
5b7ac358 338 __event_probe__compat_syscall_enter_unknown(event, id, args);
a93244f8 339 else
5b7ac358 340 __event_probe__syscall_enter_unknown(event, id, args);
f405cfce
MD
341}
342
2faf7d1b 343void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
259b6cb3 344{
a90917c3
MD
345 struct lttng_channel *chan = __data;
346 struct lttng_event *event, *unknown_event;
49c50022
MD
347 const struct trace_syscall_entry *table, *entry;
348 size_t table_len;
259b6cb3 349
b76dc1a0 350 if (unlikely(is_compat_task())) {
80f87dd2
MD
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 }
49c50022 361 table = compat_sc_table;
a93244f8 362 table_len = ARRAY_SIZE(compat_sc_table);
49c50022
MD
363 unknown_event = chan->sc_compat_unknown;
364 } else {
80f87dd2
MD
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 }
49c50022
MD
375 table = sc_table;
376 table_len = ARRAY_SIZE(sc_table);
377 unknown_event = chan->sc_unknown;
b76dc1a0 378 }
49c50022
MD
379 if (unlikely(id >= table_len)) {
380 syscall_entry_unknown(unknown_event, regs, id);
259b6cb3 381 return;
f405cfce 382 }
49c50022
MD
383 if (unlikely(is_compat_task()))
384 event = chan->compat_sc_table[id];
385 else
386 event = chan->sc_table[id];
f405cfce 387 if (unlikely(!event)) {
49c50022 388 syscall_entry_unknown(unknown_event, regs, id);
f405cfce
MD
389 return;
390 }
49c50022 391 entry = &table[id];
f405cfce 392 WARN_ON_ONCE(!entry);
259b6cb3
MD
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
5b7ac358
MD
482static void syscall_exit_unknown(struct lttng_event *event,
483 struct pt_regs *regs, unsigned int id, long ret)
484{
485 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
486
487 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
488 if (unlikely(is_compat_task()))
489 __event_probe__compat_syscall_exit_unknown(event, id, ret,
490 args);
491 else
492 __event_probe__syscall_exit_unknown(event, id, ret, args);
493}
494
495void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
496{
497 struct lttng_channel *chan = __data;
498 struct lttng_event *event, *unknown_event;
499 const struct trace_syscall_entry *table, *entry;
500 size_t table_len;
501 long id;
502
503 id = syscall_get_nr(current, regs);
504 if (unlikely(is_compat_task())) {
505 struct lttng_syscall_filter *filter;
506
507 filter = rcu_dereference(chan->sc_filter);
508 if (filter) {
509 if (id >= NR_compat_syscalls
510 || !test_bit(id, filter->sc_compat)) {
511 /* System call filtered out. */
512 return;
513 }
514 }
515 table = compat_sc_exit_table;
516 table_len = ARRAY_SIZE(compat_sc_exit_table);
517 unknown_event = chan->compat_sc_exit_unknown;
518 } else {
519 struct lttng_syscall_filter *filter;
520
521 filter = rcu_dereference(chan->sc_filter);
522 if (filter) {
523 if (id >= NR_syscalls
524 || !test_bit(id, filter->sc)) {
525 /* System call filtered out. */
526 return;
527 }
528 }
529 table = sc_exit_table;
530 table_len = ARRAY_SIZE(sc_exit_table);
531 unknown_event = chan->sc_exit_unknown;
532 }
533 if (unlikely(id >= table_len)) {
534 syscall_exit_unknown(unknown_event, regs, id, ret);
535 return;
536 }
537 if (unlikely(is_compat_task()))
538 event = chan->compat_sc_exit_table[id];
539 else
540 event = chan->sc_exit_table[id];
541 if (unlikely(!event)) {
542 syscall_exit_unknown(unknown_event, regs, id, ret);
543 return;
544 }
545 entry = &table[id];
546 WARN_ON_ONCE(!entry);
547
548 switch (entry->nrargs) {
549 case 0:
550 {
fc4f7161 551 void (*fptr)(void *__data, long ret) = entry->func;
5b7ac358 552
fc4f7161 553 fptr(event, ret);
5b7ac358
MD
554 break;
555 }
556 case 1:
557 {
558 void (*fptr)(void *__data,
fc4f7161 559 long ret,
5b7ac358
MD
560 unsigned long arg0) = entry->func;
561 unsigned long args[1];
562
563 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 564 fptr(event, ret, args[0]);
5b7ac358
MD
565 break;
566 }
567 case 2:
568 {
569 void (*fptr)(void *__data,
fc4f7161 570 long ret,
5b7ac358
MD
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);
fc4f7161 576 fptr(event, ret, args[0], args[1]);
5b7ac358
MD
577 break;
578 }
579 case 3:
580 {
581 void (*fptr)(void *__data,
fc4f7161 582 long ret,
5b7ac358
MD
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);
fc4f7161 589 fptr(event, ret, args[0], args[1], args[2]);
5b7ac358
MD
590 break;
591 }
592 case 4:
593 {
594 void (*fptr)(void *__data,
fc4f7161 595 long ret,
5b7ac358
MD
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);
fc4f7161 603 fptr(event, ret, args[0], args[1], args[2], args[3]);
5b7ac358
MD
604 break;
605 }
606 case 5:
607 {
608 void (*fptr)(void *__data,
fc4f7161 609 long ret,
5b7ac358
MD
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);
fc4f7161 618 fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
5b7ac358
MD
619 break;
620 }
621 case 6:
622 {
623 void (*fptr)(void *__data,
fc4f7161 624 long ret,
5b7ac358
MD
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);
fc4f7161 634 fptr(event, ret, args[0], args[1], args[2],
5b7ac358
MD
635 args[3], args[4], args[5]);
636 break;
637 }
638 default:
639 break;
640 }
641}
642
2a0c4816 643/* noinline to diminish caller stack size */
49c50022
MD
644static
645int fill_table(const struct trace_syscall_entry *table, size_t table_len,
5b7ac358
MD
646 struct lttng_event **chan_table, struct lttng_channel *chan,
647 void *filter, enum sc_type type)
259b6cb3 648{
2a0c4816 649 const struct lttng_event_desc *desc;
259b6cb3 650 unsigned int i;
49c50022
MD
651
652 /* Allocate events for each syscall, insert into table */
653 for (i = 0; i < table_len; i++) {
654 struct lttng_kernel_event ev;
2a0c4816 655 desc = table[i].desc;
49c50022
MD
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));
5b7ac358
MD
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);
f8695253 691 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
49c50022 692 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 693 chan_table[i] = lttng_event_create(chan, &ev, filter,
49c50022 694 desc);
abc0446a
MD
695 WARN_ON_ONCE(!chan_table[i]);
696 if (IS_ERR(chan_table[i])) {
49c50022
MD
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 */
abc0446a 703 return PTR_ERR(chan_table[i]);
49c50022
MD
704 }
705 }
706 return 0;
707}
708
a90917c3 709int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
49c50022 710{
2a0c4816 711 struct lttng_kernel_event ev;
259b6cb3
MD
712 int ret;
713
714 wrapper_vmalloc_sync_all();
259b6cb3
MD
715
716 if (!chan->sc_table) {
717 /* create syscall table mapping syscall to events */
a90917c3 718 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
259b6cb3
MD
719 * ARRAY_SIZE(sc_table), GFP_KERNEL);
720 if (!chan->sc_table)
721 return -ENOMEM;
722 }
5b7ac358
MD
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
259b6cb3 731
49c50022
MD
732#ifdef CONFIG_COMPAT
733 if (!chan->compat_sc_table) {
734 /* create syscall table mapping compat syscall to events */
a90917c3 735 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
a93244f8 736 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
49c50022
MD
737 if (!chan->compat_sc_table)
738 return -ENOMEM;
739 }
5b7ac358
MD
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 }
49c50022 748#endif
f405cfce 749 if (!chan->sc_unknown) {
f405cfce 750 const struct lttng_event_desc *desc =
5b7ac358 751 &__event_desc___syscall_enter_unknown;
2f804c0a 752
f405cfce 753 memset(&ev, 0, sizeof(ev));
f8695253
MD
754 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
755 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
f405cfce 756 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 757 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
f405cfce 758 desc);
abc0446a
MD
759 WARN_ON_ONCE(!chan->sc_unknown);
760 if (IS_ERR(chan->sc_unknown)) {
761 return PTR_ERR(chan->sc_unknown);
f405cfce
MD
762 }
763 }
764
b76dc1a0 765 if (!chan->sc_compat_unknown) {
b76dc1a0 766 const struct lttng_event_desc *desc =
5b7ac358 767 &__event_desc___compat_syscall_enter_unknown;
b76dc1a0
MD
768
769 memset(&ev, 0, sizeof(ev));
f8695253
MD
770 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
771 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
b76dc1a0 772 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 773 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
b76dc1a0 774 desc);
abc0446a
MD
775 WARN_ON_ONCE(!chan->sc_unknown);
776 if (IS_ERR(chan->sc_compat_unknown)) {
777 return PTR_ERR(chan->sc_compat_unknown);
b76dc1a0
MD
778 }
779 }
780
5b7ac358 781 if (!chan->compat_sc_exit_unknown) {
2f804c0a 782 const struct lttng_event_desc *desc =
5b7ac358 783 &__event_desc___compat_syscall_exit_unknown;
2f804c0a
MD
784
785 memset(&ev, 0, sizeof(ev));
f8695253
MD
786 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
787 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
2f804c0a 788 ev.instrumentation = LTTNG_KERNEL_NOOP;
5b7ac358
MD
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,
2f804c0a 806 desc);
5b7ac358
MD
807 WARN_ON_ONCE(!chan->sc_exit_unknown);
808 if (IS_ERR(chan->sc_exit_unknown)) {
809 return PTR_ERR(chan->sc_exit_unknown);
2f804c0a
MD
810 }
811 }
812
49c50022 813 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
5b7ac358
MD
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);
49c50022
MD
819 if (ret)
820 return ret;
5b7ac358 821
49c50022 822#ifdef CONFIG_COMPAT
a93244f8 823 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
5b7ac358
MD
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);
49c50022
MD
831 if (ret)
832 return ret;
833#endif
80f87dd2
MD
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 }
63728b02
MD
841 /*
842 * We change the name of sys_exit tracepoint due to namespace
843 * conflict with sys_exit syscall entry.
844 */
80f87dd2
MD
845 if (!chan->sys_exit_registered) {
846 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
5b7ac358 847 (void *) syscall_exit_probe, chan);
80f87dd2
MD
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;
63728b02 854 }
259b6cb3
MD
855 return ret;
856}
857
858/*
859 * Only called at session destruction.
860 */
a90917c3 861int lttng_syscalls_unregister(struct lttng_channel *chan)
259b6cb3
MD
862{
863 int ret;
864
865 if (!chan->sc_table)
866 return 0;
80f87dd2
MD
867 if (chan->sys_enter_registered) {
868 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
5b7ac358 869 (void *) syscall_exit_probe, chan);
80f87dd2
MD
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 }
a90917c3 881 /* lttng_event destroy will be performed by lttng_session_destroy() */
259b6cb3 882 kfree(chan->sc_table);
5b7ac358 883 kfree(chan->sc_exit_table);
49c50022
MD
884#ifdef CONFIG_COMPAT
885 kfree(chan->compat_sc_table);
5b7ac358 886 kfree(chan->compat_sc_exit_table);
49c50022 887#endif
80f87dd2
MD
888 kfree(chan->sc_filter);
889 return 0;
890}
891
892static
893int get_syscall_nr(const char *syscall_name)
894{
895 int syscall_nr = -1;
896 int i;
897
898 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
899 const struct trace_syscall_entry *entry;
5b7ac358 900 const char *it_name;
80f87dd2
MD
901
902 entry = &sc_table[i];
903 if (!entry->desc)
904 continue;
5b7ac358
MD
905 it_name = entry->desc->name;
906 it_name += strlen(SYSCALL_ENTRY_STR);
907 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
908 syscall_nr = i;
909 break;
910 }
911 }
912 return syscall_nr;
913}
914
915static
916int get_compat_syscall_nr(const char *syscall_name)
917{
918 int syscall_nr = -1;
919 int i;
920
921 for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++) {
922 const struct trace_syscall_entry *entry;
5b7ac358 923 const char *it_name;
80f87dd2
MD
924
925 entry = &compat_sc_table[i];
926 if (!entry->desc)
927 continue;
5b7ac358
MD
928 it_name = entry->desc->name;
929 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
930 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
931 syscall_nr = i;
932 break;
933 }
934 }
935 return syscall_nr;
936}
937
938int lttng_syscall_filter_enable(struct lttng_channel *chan,
939 const char *name)
940{
941 int syscall_nr, compat_syscall_nr, ret;
942 struct lttng_syscall_filter *filter;
943
944 WARN_ON_ONCE(!chan->sc_table);
945
946 if (!name) {
947 /* Enable all system calls by removing filter */
948 if (chan->sc_filter) {
949 filter = chan->sc_filter;
950 rcu_assign_pointer(chan->sc_filter, NULL);
951 synchronize_trace();
952 kfree(filter);
953 }
954 chan->syscall_all = 1;
955 return 0;
956 }
957
958 if (!chan->sc_filter) {
959 if (chan->syscall_all) {
960 /*
961 * All syscalls are already enabled.
962 */
963 return -EEXIST;
964 }
965 filter = kzalloc(sizeof(struct lttng_syscall_filter),
966 GFP_KERNEL);
967 if (!filter)
968 return -ENOMEM;
969 } else {
970 filter = chan->sc_filter;
971 }
972 syscall_nr = get_syscall_nr(name);
973 compat_syscall_nr = get_compat_syscall_nr(name);
974 if (syscall_nr < 0 && compat_syscall_nr < 0) {
975 ret = -ENOENT;
976 goto error;
977 }
978 if (syscall_nr >= 0) {
979 if (test_bit(syscall_nr, filter->sc)) {
980 ret = -EEXIST;
981 goto error;
982 }
983 bitmap_set(filter->sc, syscall_nr, 1);
984 }
985 if (compat_syscall_nr >= 0) {
986 if (test_bit(compat_syscall_nr, filter->sc_compat)) {
987 ret = -EEXIST;
988 goto error;
989 }
990 bitmap_set(filter->sc_compat, compat_syscall_nr, 1);
991 }
992 if (!chan->sc_filter)
993 rcu_assign_pointer(chan->sc_filter, filter);
994 return 0;
995
996error:
997 if (!chan->sc_filter)
998 kfree(filter);
999 return ret;
1000}
1001
1002int lttng_syscall_filter_disable(struct lttng_channel *chan,
1003 const char *name)
1004{
1005 int syscall_nr, compat_syscall_nr, ret;
1006 struct lttng_syscall_filter *filter;
1007
1008 WARN_ON_ONCE(!chan->sc_table);
1009
1010 if (!chan->sc_filter) {
1011 filter = kzalloc(sizeof(struct lttng_syscall_filter),
1012 GFP_KERNEL);
1013 if (!filter)
1014 return -ENOMEM;
1015 /* Trace all system calls, then apply disable. */
1016 bitmap_set(filter->sc, 0, NR_syscalls);
1017 bitmap_set(filter->sc_compat, 0, NR_compat_syscalls);
1018 } else {
1019 filter = chan->sc_filter;
1020 }
1021
1022 syscall_nr = get_syscall_nr(name);
1023 compat_syscall_nr = get_compat_syscall_nr(name);
1024 if (syscall_nr < 0 && compat_syscall_nr < 0) {
1025 ret = -ENOENT;
1026 goto error;
1027 }
1028 if (syscall_nr >= 0) {
1029 if (!test_bit(syscall_nr, chan->sc_filter->sc)) {
1030 ret = -EEXIST;
1031 goto error;
1032 }
1033 bitmap_clear(chan->sc_filter->sc, syscall_nr, 1);
1034 }
1035 if (compat_syscall_nr >= 0) {
1036 if (!test_bit(compat_syscall_nr, chan->sc_filter->sc_compat)) {
1037 ret = -EEXIST;
1038 goto error;
1039 }
1040 bitmap_clear(chan->sc_filter->sc_compat, compat_syscall_nr, 1);
1041 }
1042 if (!chan->sc_filter)
1043 rcu_assign_pointer(chan->sc_filter, filter);
1044 chan->syscall_all = 0;
259b6cb3 1045 return 0;
80f87dd2
MD
1046
1047error:
1048 if (!chan->sc_filter)
1049 kfree(filter);
1050 return ret;
259b6cb3 1051}
This page took 0.070931 seconds and 4 git commands to generate.