Fix: writeback instrumentation for 4.2 kernels
[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>
7ca580f8
MD
28#include <linux/in.h>
29#include <linux/in6.h>
2d2464bd 30#include <linux/seq_file.h>
d4291869 31#include <linux/stringify.h>
082d4946
MD
32#include <linux/file.h>
33#include <linux/anon_inodes.h>
259b6cb3
MD
34#include <asm/ptrace.h>
35#include <asm/syscall.h>
36
12e579db 37#include "lib/bitfield.h"
3a523f5b 38#include "wrapper/tracepoint.h"
4ac10b76 39#include "wrapper/file.h"
49e2f4c4 40#include "wrapper/rcu.h"
a90917c3 41#include "lttng-events.h"
259b6cb3 42
6333ace3 43#ifndef CONFIG_COMPAT
bfa949bf
MD
44# ifndef is_compat_task
45# define is_compat_task() (0)
46# endif
6333ace3
MD
47#endif
48
5b7ac358
MD
49enum sc_type {
50 SC_TYPE_ENTRY,
51 SC_TYPE_EXIT,
52 SC_TYPE_COMPAT_ENTRY,
53 SC_TYPE_COMPAT_EXIT,
54};
55
d4291869
MD
56#define SYSCALL_ENTRY_TOK syscall_entry_
57#define COMPAT_SYSCALL_ENTRY_TOK compat_syscall_entry_
58#define SYSCALL_EXIT_TOK syscall_exit_
59#define COMPAT_SYSCALL_EXIT_TOK compat_syscall_exit_
60
61#define SYSCALL_ENTRY_STR __stringify(SYSCALL_ENTRY_TOK)
62#define COMPAT_SYSCALL_ENTRY_STR __stringify(COMPAT_SYSCALL_ENTRY_TOK)
63#define SYSCALL_EXIT_STR __stringify(SYSCALL_EXIT_TOK)
64#define COMPAT_SYSCALL_EXIT_STR __stringify(COMPAT_SYSCALL_EXIT_TOK)
5b7ac358 65
a93244f8 66static
2faf7d1b 67void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
5b7ac358
MD
68static
69void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
259b6cb3 70
3a523f5b
MD
71/*
72 * Forward declarations for old kernels.
73 */
74struct mmsghdr;
75struct rlimit64;
76struct oldold_utsname;
77struct old_utsname;
78struct sel_arg_struct;
79struct mmap_arg_struct;
c0b71117 80struct file_handle;
3a523f5b 81
80f87dd2
MD
82#ifdef IA32_NR_syscalls
83#define NR_compat_syscalls IA32_NR_syscalls
84#else
85#define NR_compat_syscalls NR_syscalls
86#endif
87
259b6cb3
MD
88/*
89 * Create LTTng tracepoint probes.
90 */
91#define LTTNG_PACKAGE_BUILD
92#define CREATE_TRACE_POINTS
2655f9ad 93#define TP_MODULE_NOINIT
2f804c0a 94#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
259b6cb3 95
a93244f8
MD
96#define PARAMS(args...) args
97
5b7ac358 98/* Handle unknown syscalls */
72a52753 99#undef TRACE_SYSTEM
5b7ac358
MD
100#define TRACE_SYSTEM syscalls_unknown
101#include "instrumentation/syscalls/headers/syscalls_unknown.h"
102#undef TRACE_SYSTEM
103
fc4f7161
MD
104#define SC_ENTER
105
fc4f7161
MD
106#undef sc_exit
107#define sc_exit(...)
b75d00c4
MD
108#undef sc_in
109#define sc_in(...) __VA_ARGS__
110#undef sc_out
111#define sc_out(...)
112#undef sc_inout
113#define sc_inout(...) __VA_ARGS__
5b7ac358
MD
114
115/* Hijack probe callback for system call enter */
a93244f8 116#undef TP_PROBE_CB
259b6cb3 117#define TP_PROBE_CB(_template) &syscall_entry_probe
57ede728 118#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
d4291869 119 LTTNG_TRACEPOINT_EVENT(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
57ede728
MD
120 PARAMS(_fields))
121#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \
d4291869 122 LTTNG_TRACEPOINT_EVENT_CODE(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
cb3ef14c 123 PARAMS(_locvar), PARAMS(_code), \
57ede728
MD
124 PARAMS(_fields))
125#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
126 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_entry_##_name, PARAMS(_fields))
cb3ef14c 127#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
d4291869 128 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_entry_##_template, syscall_entry_##_name)
a93244f8 129#undef TRACE_SYSTEM
d4291869 130#define TRACE_SYSTEM syscall_entry_integers
5b7ac358 131#define TRACE_INCLUDE_FILE syscalls_integers
177b3692 132#include "instrumentation/syscalls/headers/syscalls_integers.h"
5b7ac358 133#undef TRACE_INCLUDE_FILE
a93244f8 134#undef TRACE_SYSTEM
d4291869 135#define TRACE_SYSTEM syscall_entry_pointers
5b7ac358 136#define TRACE_INCLUDE_FILE syscalls_pointers
177b3692 137#include "instrumentation/syscalls/headers/syscalls_pointers.h"
5b7ac358 138#undef TRACE_INCLUDE_FILE
a93244f8 139#undef TRACE_SYSTEM
cb3ef14c
MD
140#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
141#undef SC_LTTNG_TRACEPOINT_EVENT
142#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
143#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
5b7ac358 144#undef TP_PROBE_CB
3bc29f0a
MD
145#undef _TRACE_SYSCALLS_INTEGERS_H
146#undef _TRACE_SYSCALLS_POINTERS_H
5b7ac358
MD
147
148/* Hijack probe callback for compat system call enter */
a93244f8 149#define TP_PROBE_CB(_template) &syscall_entry_probe
57ede728 150#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
d4291869 151 LTTNG_TRACEPOINT_EVENT(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
57ede728
MD
152 PARAMS(_fields))
153#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \
d4291869 154 LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
57ede728
MD
155 PARAMS(_locvar), PARAMS(_code), PARAMS(_fields))
156#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
157 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_entry_##_name, PARAMS(_fields))
cb3ef14c 158#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
d4291869
MD
159 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_entry_##_template, \
160 compat_syscall_entry_##_name)
161#define TRACE_SYSTEM compat_syscall_entry_integers
5b7ac358
MD
162#define TRACE_INCLUDE_FILE compat_syscalls_integers
163#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
164#undef TRACE_INCLUDE_FILE
165#undef TRACE_SYSTEM
d4291869 166#define TRACE_SYSTEM compat_syscall_entry_pointers
5b7ac358
MD
167#define TRACE_INCLUDE_FILE compat_syscalls_pointers
168#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
169#undef TRACE_INCLUDE_FILE
170#undef TRACE_SYSTEM
cb3ef14c
MD
171#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
172#undef SC_LTTNG_TRACEPOINT_EVENT
173#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
174#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
5b7ac358 175#undef TP_PROBE_CB
3bc29f0a
MD
176#undef _TRACE_SYSCALLS_INTEGERS_H
177#undef _TRACE_SYSCALLS_POINTERS_H
5b7ac358 178
fc4f7161
MD
179#undef SC_ENTER
180
181#define SC_EXIT
182
fc4f7161
MD
183#undef sc_exit
184#define sc_exit(...) __VA_ARGS__
b75d00c4
MD
185#undef sc_in
186#define sc_in(...)
187#undef sc_out
188#define sc_out(...) __VA_ARGS__
189#undef sc_inout
190#define sc_inout(...) __VA_ARGS__
5b7ac358
MD
191
192/* Hijack probe callback for system call exit */
193#define TP_PROBE_CB(_template) &syscall_exit_probe
57ede728 194#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
3bc29f0a 195 LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
57ede728
MD
196 PARAMS(_fields))
197#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \
3bc29f0a 198 LTTNG_TRACEPOINT_EVENT_CODE(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
57ede728
MD
199 PARAMS(_locvar), PARAMS(_code), PARAMS(_fields))
200#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
201 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_fields))
cb3ef14c
MD
202#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
203 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_exit_##_template, \
5b7ac358
MD
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
cb3ef14c
MD
215#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
216#undef SC_LTTNG_TRACEPOINT_EVENT
217#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
218#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
5b7ac358 219#undef TP_PROBE_CB
3bc29f0a
MD
220#undef _TRACE_SYSCALLS_INTEGERS_H
221#undef _TRACE_SYSCALLS_POINTERS_H
5b7ac358
MD
222
223
224/* Hijack probe callback for compat system call exit */
225#define TP_PROBE_CB(_template) &syscall_exit_probe
57ede728 226#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
3bc29f0a 227 LTTNG_TRACEPOINT_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
57ede728
MD
228 PARAMS(_fields))
229#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \
3bc29f0a 230 LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
57ede728
MD
231 PARAMS(_locvar), PARAMS(_code), PARAMS(_fields))
232#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
233 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_fields))
cb3ef14c 234#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
3bc29f0a 235 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_exit_##_template, \
5b7ac358
MD
236 compat_syscall_exit_##_name)
237#define TRACE_SYSTEM compat_syscall_exit_integers
238#define TRACE_INCLUDE_FILE compat_syscalls_integers
a93244f8 239#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
5b7ac358 240#undef TRACE_INCLUDE_FILE
a93244f8 241#undef TRACE_SYSTEM
5b7ac358
MD
242#define TRACE_SYSTEM compat_syscall_exit_pointers
243#define TRACE_INCLUDE_FILE compat_syscalls_pointers
a93244f8 244#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
5b7ac358 245#undef TRACE_INCLUDE_FILE
a93244f8 246#undef TRACE_SYSTEM
cb3ef14c
MD
247#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
248#undef SC_LTTNG_TRACEPOINT_EVENT
249#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
250#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
a93244f8 251#undef TP_PROBE_CB
3bc29f0a
MD
252#undef _TRACE_SYSCALLS_INTEGERS_H
253#undef _TRACE_SYSCALLS_POINTERS_H
5b7ac358 254
fc4f7161 255#undef SC_EXIT
259b6cb3 256
2655f9ad 257#undef TP_MODULE_NOINIT
259b6cb3
MD
258#undef LTTNG_PACKAGE_BUILD
259#undef CREATE_TRACE_POINTS
260
a93244f8
MD
261struct trace_syscall_entry {
262 void *func;
263 const struct lttng_event_desc *desc;
264 const struct lttng_event_field *fields;
265 unsigned int nrargs;
266};
267
268#define CREATE_SYSCALL_TABLE
269
fc4f7161
MD
270#define SC_ENTER
271
272#undef sc_exit
273#define sc_exit(...)
274
259b6cb3 275#undef TRACE_SYSCALL_TABLE
f7bdf4db 276#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259b6cb3 277 [ _nr ] = { \
d4291869 278 .func = __event_probe__syscall_entry_##_template, \
259b6cb3 279 .nrargs = (_nrargs), \
d4291869
MD
280 .fields = __event_fields___syscall_entry_##_template, \
281 .desc = &__event_desc___syscall_entry_##_name, \
259b6cb3
MD
282 },
283
5b7ac358 284/* Syscall enter tracing table */
49c50022 285static const struct trace_syscall_entry sc_table[] = {
177b3692
MD
286#include "instrumentation/syscalls/headers/syscalls_integers.h"
287#include "instrumentation/syscalls/headers/syscalls_pointers.h"
259b6cb3
MD
288};
289
a93244f8
MD
290#undef TRACE_SYSCALL_TABLE
291#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
292 [ _nr ] = { \
d4291869 293 .func = __event_probe__compat_syscall_entry_##_template, \
a93244f8 294 .nrargs = (_nrargs), \
d4291869
MD
295 .fields = __event_fields___compat_syscall_entry_##_template, \
296 .desc = &__event_desc___compat_syscall_entry_##_name, \
a93244f8
MD
297 },
298
5b7ac358 299/* Compat syscall enter table */
a93244f8
MD
300const struct trace_syscall_entry compat_sc_table[] = {
301#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
302#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
303};
259b6cb3 304
fc4f7161
MD
305#undef SC_ENTER
306
307#define SC_EXIT
308
309#undef sc_exit
310#define sc_exit(...) __VA_ARGS__
311
5b7ac358
MD
312#undef TRACE_SYSCALL_TABLE
313#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
314 [ _nr ] = { \
315 .func = __event_probe__syscall_exit_##_template, \
316 .nrargs = (_nrargs), \
317 .fields = __event_fields___syscall_exit_##_template, \
318 .desc = &__event_desc___syscall_exit_##_name, \
319 },
320
321/* Syscall exit table */
322static const struct trace_syscall_entry sc_exit_table[] = {
323#include "instrumentation/syscalls/headers/syscalls_integers.h"
324#include "instrumentation/syscalls/headers/syscalls_pointers.h"
325};
326
327#undef TRACE_SYSCALL_TABLE
328#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
329 [ _nr ] = { \
330 .func = __event_probe__compat_syscall_exit_##_template, \
331 .nrargs = (_nrargs), \
332 .fields = __event_fields___compat_syscall_exit_##_template, \
333 .desc = &__event_desc___compat_syscall_exit_##_name, \
334 },
335
336/* Compat syscall exit table */
337const struct trace_syscall_entry compat_sc_exit_table[] = {
338#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
339#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
340};
341
fc4f7161
MD
342#undef SC_EXIT
343
a93244f8 344#undef CREATE_SYSCALL_TABLE
2faf7d1b 345
80f87dd2
MD
346struct lttng_syscall_filter {
347 DECLARE_BITMAP(sc, NR_syscalls);
348 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
349};
350
a90917c3 351static void syscall_entry_unknown(struct lttng_event *event,
f405cfce
MD
352 struct pt_regs *regs, unsigned int id)
353{
354 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
f405cfce 355
f405cfce 356 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
a93244f8 357 if (unlikely(is_compat_task()))
d4291869 358 __event_probe__compat_syscall_entry_unknown(event, id, args);
a93244f8 359 else
d4291869 360 __event_probe__syscall_entry_unknown(event, id, args);
f405cfce
MD
361}
362
2faf7d1b 363void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
259b6cb3 364{
a90917c3
MD
365 struct lttng_channel *chan = __data;
366 struct lttng_event *event, *unknown_event;
49c50022
MD
367 const struct trace_syscall_entry *table, *entry;
368 size_t table_len;
259b6cb3 369
b76dc1a0 370 if (unlikely(is_compat_task())) {
80f87dd2
MD
371 struct lttng_syscall_filter *filter;
372
49e2f4c4 373 filter = lttng_rcu_dereference(chan->sc_filter);
80f87dd2 374 if (filter) {
74f7b56a 375 if (id < 0 || id >= NR_compat_syscalls
80f87dd2
MD
376 || !test_bit(id, filter->sc_compat)) {
377 /* System call filtered out. */
378 return;
379 }
380 }
49c50022 381 table = compat_sc_table;
a93244f8 382 table_len = ARRAY_SIZE(compat_sc_table);
49c50022
MD
383 unknown_event = chan->sc_compat_unknown;
384 } else {
80f87dd2
MD
385 struct lttng_syscall_filter *filter;
386
49e2f4c4 387 filter = lttng_rcu_dereference(chan->sc_filter);
80f87dd2 388 if (filter) {
74f7b56a 389 if (id < 0 || id >= NR_syscalls
80f87dd2
MD
390 || !test_bit(id, filter->sc)) {
391 /* System call filtered out. */
392 return;
393 }
394 }
49c50022
MD
395 table = sc_table;
396 table_len = ARRAY_SIZE(sc_table);
397 unknown_event = chan->sc_unknown;
b76dc1a0 398 }
74f7b56a 399 if (unlikely(id < 0 || id >= table_len)) {
49c50022 400 syscall_entry_unknown(unknown_event, regs, id);
259b6cb3 401 return;
f405cfce 402 }
49c50022
MD
403 if (unlikely(is_compat_task()))
404 event = chan->compat_sc_table[id];
405 else
406 event = chan->sc_table[id];
f405cfce 407 if (unlikely(!event)) {
49c50022 408 syscall_entry_unknown(unknown_event, regs, id);
f405cfce
MD
409 return;
410 }
49c50022 411 entry = &table[id];
f405cfce 412 WARN_ON_ONCE(!entry);
259b6cb3
MD
413
414 switch (entry->nrargs) {
415 case 0:
416 {
417 void (*fptr)(void *__data) = entry->func;
418
419 fptr(event);
420 break;
421 }
422 case 1:
423 {
424 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
425 unsigned long args[1];
426
427 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
428 fptr(event, args[0]);
429 break;
430 }
431 case 2:
432 {
433 void (*fptr)(void *__data,
434 unsigned long arg0,
435 unsigned long arg1) = entry->func;
436 unsigned long args[2];
437
438 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
439 fptr(event, args[0], args[1]);
440 break;
441 }
442 case 3:
443 {
444 void (*fptr)(void *__data,
445 unsigned long arg0,
446 unsigned long arg1,
447 unsigned long arg2) = entry->func;
448 unsigned long args[3];
449
450 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
451 fptr(event, args[0], args[1], args[2]);
452 break;
453 }
454 case 4:
455 {
456 void (*fptr)(void *__data,
457 unsigned long arg0,
458 unsigned long arg1,
459 unsigned long arg2,
460 unsigned long arg3) = entry->func;
461 unsigned long args[4];
462
463 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
464 fptr(event, args[0], args[1], args[2], args[3]);
465 break;
466 }
467 case 5:
468 {
469 void (*fptr)(void *__data,
470 unsigned long arg0,
471 unsigned long arg1,
472 unsigned long arg2,
473 unsigned long arg3,
474 unsigned long arg4) = entry->func;
475 unsigned long args[5];
476
477 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
478 fptr(event, args[0], args[1], args[2], args[3], args[4]);
479 break;
480 }
481 case 6:
482 {
483 void (*fptr)(void *__data,
484 unsigned long arg0,
485 unsigned long arg1,
486 unsigned long arg2,
487 unsigned long arg3,
488 unsigned long arg4,
489 unsigned long arg5) = entry->func;
490 unsigned long args[6];
491
492 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
493 fptr(event, args[0], args[1], args[2],
494 args[3], args[4], args[5]);
495 break;
496 }
497 default:
498 break;
499 }
500}
501
5b7ac358 502static void syscall_exit_unknown(struct lttng_event *event,
74f7b56a 503 struct pt_regs *regs, int id, long ret)
5b7ac358
MD
504{
505 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
506
507 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
508 if (unlikely(is_compat_task()))
509 __event_probe__compat_syscall_exit_unknown(event, id, ret,
510 args);
511 else
512 __event_probe__syscall_exit_unknown(event, id, ret, args);
513}
514
515void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
516{
517 struct lttng_channel *chan = __data;
518 struct lttng_event *event, *unknown_event;
519 const struct trace_syscall_entry *table, *entry;
520 size_t table_len;
521 long id;
522
523 id = syscall_get_nr(current, regs);
524 if (unlikely(is_compat_task())) {
525 struct lttng_syscall_filter *filter;
526
49e2f4c4 527 filter = lttng_rcu_dereference(chan->sc_filter);
5b7ac358 528 if (filter) {
74f7b56a 529 if (id < 0 || id >= NR_compat_syscalls
5b7ac358
MD
530 || !test_bit(id, filter->sc_compat)) {
531 /* System call filtered out. */
532 return;
533 }
534 }
535 table = compat_sc_exit_table;
536 table_len = ARRAY_SIZE(compat_sc_exit_table);
537 unknown_event = chan->compat_sc_exit_unknown;
538 } else {
539 struct lttng_syscall_filter *filter;
540
49e2f4c4 541 filter = lttng_rcu_dereference(chan->sc_filter);
5b7ac358 542 if (filter) {
74f7b56a 543 if (id < 0 || id >= NR_syscalls
5b7ac358
MD
544 || !test_bit(id, filter->sc)) {
545 /* System call filtered out. */
546 return;
547 }
548 }
549 table = sc_exit_table;
550 table_len = ARRAY_SIZE(sc_exit_table);
551 unknown_event = chan->sc_exit_unknown;
552 }
74f7b56a 553 if (unlikely(id < 0 || id >= table_len)) {
5b7ac358
MD
554 syscall_exit_unknown(unknown_event, regs, id, ret);
555 return;
556 }
557 if (unlikely(is_compat_task()))
558 event = chan->compat_sc_exit_table[id];
559 else
560 event = chan->sc_exit_table[id];
561 if (unlikely(!event)) {
562 syscall_exit_unknown(unknown_event, regs, id, ret);
563 return;
564 }
565 entry = &table[id];
566 WARN_ON_ONCE(!entry);
567
568 switch (entry->nrargs) {
569 case 0:
570 {
fc4f7161 571 void (*fptr)(void *__data, long ret) = entry->func;
5b7ac358 572
fc4f7161 573 fptr(event, ret);
5b7ac358
MD
574 break;
575 }
576 case 1:
577 {
578 void (*fptr)(void *__data,
fc4f7161 579 long ret,
5b7ac358
MD
580 unsigned long arg0) = entry->func;
581 unsigned long args[1];
582
583 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 584 fptr(event, ret, args[0]);
5b7ac358
MD
585 break;
586 }
587 case 2:
588 {
589 void (*fptr)(void *__data,
fc4f7161 590 long ret,
5b7ac358
MD
591 unsigned long arg0,
592 unsigned long arg1) = entry->func;
593 unsigned long args[2];
594
595 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 596 fptr(event, ret, args[0], args[1]);
5b7ac358
MD
597 break;
598 }
599 case 3:
600 {
601 void (*fptr)(void *__data,
fc4f7161 602 long ret,
5b7ac358
MD
603 unsigned long arg0,
604 unsigned long arg1,
605 unsigned long arg2) = entry->func;
606 unsigned long args[3];
607
608 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 609 fptr(event, ret, args[0], args[1], args[2]);
5b7ac358
MD
610 break;
611 }
612 case 4:
613 {
614 void (*fptr)(void *__data,
fc4f7161 615 long ret,
5b7ac358
MD
616 unsigned long arg0,
617 unsigned long arg1,
618 unsigned long arg2,
619 unsigned long arg3) = entry->func;
620 unsigned long args[4];
621
622 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 623 fptr(event, ret, args[0], args[1], args[2], args[3]);
5b7ac358
MD
624 break;
625 }
626 case 5:
627 {
628 void (*fptr)(void *__data,
fc4f7161 629 long ret,
5b7ac358
MD
630 unsigned long arg0,
631 unsigned long arg1,
632 unsigned long arg2,
633 unsigned long arg3,
634 unsigned long arg4) = entry->func;
635 unsigned long args[5];
636
637 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 638 fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
5b7ac358
MD
639 break;
640 }
641 case 6:
642 {
643 void (*fptr)(void *__data,
fc4f7161 644 long ret,
5b7ac358
MD
645 unsigned long arg0,
646 unsigned long arg1,
647 unsigned long arg2,
648 unsigned long arg3,
649 unsigned long arg4,
650 unsigned long arg5) = entry->func;
651 unsigned long args[6];
652
653 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
fc4f7161 654 fptr(event, ret, args[0], args[1], args[2],
5b7ac358
MD
655 args[3], args[4], args[5]);
656 break;
657 }
658 default:
659 break;
660 }
661}
662
33a39a3c
MD
663/*
664 * noinline to diminish caller stack size.
665 * Should be called with sessions lock held.
666 */
49c50022
MD
667static
668int fill_table(const struct trace_syscall_entry *table, size_t table_len,
5b7ac358
MD
669 struct lttng_event **chan_table, struct lttng_channel *chan,
670 void *filter, enum sc_type type)
259b6cb3 671{
2a0c4816 672 const struct lttng_event_desc *desc;
259b6cb3 673 unsigned int i;
49c50022
MD
674
675 /* Allocate events for each syscall, insert into table */
676 for (i = 0; i < table_len; i++) {
677 struct lttng_kernel_event ev;
2a0c4816 678 desc = table[i].desc;
49c50022
MD
679
680 if (!desc) {
681 /* Unknown syscall */
682 continue;
683 }
684 /*
685 * Skip those already populated by previous failed
686 * register for this channel.
687 */
688 if (chan_table[i])
689 continue;
690 memset(&ev, 0, sizeof(ev));
5b7ac358
MD
691 switch (type) {
692 case SC_TYPE_ENTRY:
693 strncpy(ev.name, SYSCALL_ENTRY_STR,
694 LTTNG_KERNEL_SYM_NAME_LEN);
695 break;
696 case SC_TYPE_EXIT:
697 strncpy(ev.name, SYSCALL_EXIT_STR,
698 LTTNG_KERNEL_SYM_NAME_LEN);
699 break;
700 case SC_TYPE_COMPAT_ENTRY:
701 strncpy(ev.name, COMPAT_SYSCALL_ENTRY_STR,
702 LTTNG_KERNEL_SYM_NAME_LEN);
703 break;
704 case SC_TYPE_COMPAT_EXIT:
705 strncpy(ev.name, COMPAT_SYSCALL_EXIT_STR,
706 LTTNG_KERNEL_SYM_NAME_LEN);
707 break;
708 default:
709 BUG_ON(1);
710 break;
711 }
712 strncat(ev.name, desc->name,
713 LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1);
f8695253 714 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
33a39a3c
MD
715 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
716 chan_table[i] = _lttng_event_create(chan, &ev, filter,
3c997079 717 desc, ev.instrumentation);
abc0446a
MD
718 WARN_ON_ONCE(!chan_table[i]);
719 if (IS_ERR(chan_table[i])) {
49c50022
MD
720 /*
721 * If something goes wrong in event registration
722 * after the first one, we have no choice but to
723 * leave the previous events in there, until
724 * deleted by session teardown.
725 */
abc0446a 726 return PTR_ERR(chan_table[i]);
49c50022
MD
727 }
728 }
729 return 0;
730}
731
33a39a3c
MD
732/*
733 * Should be called with sessions lock held.
734 */
a90917c3 735int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
49c50022 736{
2a0c4816 737 struct lttng_kernel_event ev;
259b6cb3
MD
738 int ret;
739
740 wrapper_vmalloc_sync_all();
259b6cb3
MD
741
742 if (!chan->sc_table) {
743 /* create syscall table mapping syscall to events */
a90917c3 744 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
259b6cb3
MD
745 * ARRAY_SIZE(sc_table), GFP_KERNEL);
746 if (!chan->sc_table)
747 return -ENOMEM;
748 }
5b7ac358
MD
749 if (!chan->sc_exit_table) {
750 /* create syscall table mapping syscall to events */
751 chan->sc_exit_table = kzalloc(sizeof(struct lttng_event *)
752 * ARRAY_SIZE(sc_exit_table), GFP_KERNEL);
753 if (!chan->sc_exit_table)
754 return -ENOMEM;
755 }
756
259b6cb3 757
49c50022
MD
758#ifdef CONFIG_COMPAT
759 if (!chan->compat_sc_table) {
760 /* create syscall table mapping compat syscall to events */
a90917c3 761 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
a93244f8 762 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
49c50022
MD
763 if (!chan->compat_sc_table)
764 return -ENOMEM;
765 }
5b7ac358
MD
766
767 if (!chan->compat_sc_exit_table) {
768 /* create syscall table mapping compat syscall to events */
769 chan->compat_sc_exit_table = kzalloc(sizeof(struct lttng_event *)
770 * ARRAY_SIZE(compat_sc_exit_table), GFP_KERNEL);
771 if (!chan->compat_sc_exit_table)
772 return -ENOMEM;
773 }
49c50022 774#endif
f405cfce 775 if (!chan->sc_unknown) {
f405cfce 776 const struct lttng_event_desc *desc =
d4291869 777 &__event_desc___syscall_entry_unknown;
2f804c0a 778
f405cfce 779 memset(&ev, 0, sizeof(ev));
f8695253
MD
780 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
781 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
33a39a3c
MD
782 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
783 chan->sc_unknown = _lttng_event_create(chan, &ev, filter,
3c997079
MD
784 desc,
785 ev.instrumentation);
abc0446a
MD
786 WARN_ON_ONCE(!chan->sc_unknown);
787 if (IS_ERR(chan->sc_unknown)) {
788 return PTR_ERR(chan->sc_unknown);
f405cfce
MD
789 }
790 }
791
b76dc1a0 792 if (!chan->sc_compat_unknown) {
b76dc1a0 793 const struct lttng_event_desc *desc =
d4291869 794 &__event_desc___compat_syscall_entry_unknown;
b76dc1a0
MD
795
796 memset(&ev, 0, sizeof(ev));
f8695253
MD
797 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
798 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
33a39a3c
MD
799 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
800 chan->sc_compat_unknown = _lttng_event_create(chan, &ev, filter,
3c997079
MD
801 desc,
802 ev.instrumentation);
abc0446a
MD
803 WARN_ON_ONCE(!chan->sc_unknown);
804 if (IS_ERR(chan->sc_compat_unknown)) {
805 return PTR_ERR(chan->sc_compat_unknown);
b76dc1a0
MD
806 }
807 }
808
5b7ac358 809 if (!chan->compat_sc_exit_unknown) {
2f804c0a 810 const struct lttng_event_desc *desc =
5b7ac358 811 &__event_desc___compat_syscall_exit_unknown;
2f804c0a
MD
812
813 memset(&ev, 0, sizeof(ev));
f8695253
MD
814 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
815 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
33a39a3c
MD
816 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
817 chan->compat_sc_exit_unknown = _lttng_event_create(chan, &ev,
3c997079
MD
818 filter, desc,
819 ev.instrumentation);
5b7ac358
MD
820 WARN_ON_ONCE(!chan->compat_sc_exit_unknown);
821 if (IS_ERR(chan->compat_sc_exit_unknown)) {
822 return PTR_ERR(chan->compat_sc_exit_unknown);
823 }
824 }
825
826 if (!chan->sc_exit_unknown) {
827 const struct lttng_event_desc *desc =
828 &__event_desc___syscall_exit_unknown;
829
830 memset(&ev, 0, sizeof(ev));
831 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
832 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
33a39a3c
MD
833 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
834 chan->sc_exit_unknown = _lttng_event_create(chan, &ev, filter,
3c997079 835 desc, ev.instrumentation);
5b7ac358
MD
836 WARN_ON_ONCE(!chan->sc_exit_unknown);
837 if (IS_ERR(chan->sc_exit_unknown)) {
838 return PTR_ERR(chan->sc_exit_unknown);
2f804c0a
MD
839 }
840 }
841
49c50022 842 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
5b7ac358
MD
843 chan->sc_table, chan, filter, SC_TYPE_ENTRY);
844 if (ret)
845 return ret;
846 ret = fill_table(sc_exit_table, ARRAY_SIZE(sc_exit_table),
847 chan->sc_exit_table, chan, filter, SC_TYPE_EXIT);
49c50022
MD
848 if (ret)
849 return ret;
5b7ac358 850
49c50022 851#ifdef CONFIG_COMPAT
a93244f8 852 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
5b7ac358
MD
853 chan->compat_sc_table, chan, filter,
854 SC_TYPE_COMPAT_ENTRY);
855 if (ret)
856 return ret;
857 ret = fill_table(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
858 chan->compat_sc_exit_table, chan, filter,
859 SC_TYPE_COMPAT_EXIT);
49c50022
MD
860 if (ret)
861 return ret;
862#endif
80f87dd2
MD
863 if (!chan->sys_enter_registered) {
864 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
865 (void *) syscall_entry_probe, chan);
866 if (ret)
867 return ret;
868 chan->sys_enter_registered = 1;
869 }
63728b02
MD
870 /*
871 * We change the name of sys_exit tracepoint due to namespace
872 * conflict with sys_exit syscall entry.
873 */
80f87dd2
MD
874 if (!chan->sys_exit_registered) {
875 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
5b7ac358 876 (void *) syscall_exit_probe, chan);
80f87dd2
MD
877 if (ret) {
878 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
879 (void *) syscall_entry_probe, chan));
880 return ret;
881 }
882 chan->sys_exit_registered = 1;
63728b02 883 }
259b6cb3
MD
884 return ret;
885}
886
887/*
888 * Only called at session destruction.
889 */
a90917c3 890int lttng_syscalls_unregister(struct lttng_channel *chan)
259b6cb3
MD
891{
892 int ret;
893
894 if (!chan->sc_table)
895 return 0;
80f87dd2
MD
896 if (chan->sys_enter_registered) {
897 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
5b7ac358 898 (void *) syscall_exit_probe, chan);
80f87dd2
MD
899 if (ret)
900 return ret;
901 chan->sys_enter_registered = 0;
902 }
903 if (chan->sys_exit_registered) {
904 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
905 (void *) syscall_entry_probe, chan);
906 if (ret)
907 return ret;
908 chan->sys_exit_registered = 0;
909 }
a90917c3 910 /* lttng_event destroy will be performed by lttng_session_destroy() */
259b6cb3 911 kfree(chan->sc_table);
5b7ac358 912 kfree(chan->sc_exit_table);
49c50022
MD
913#ifdef CONFIG_COMPAT
914 kfree(chan->compat_sc_table);
5b7ac358 915 kfree(chan->compat_sc_exit_table);
49c50022 916#endif
80f87dd2
MD
917 kfree(chan->sc_filter);
918 return 0;
919}
920
921static
922int get_syscall_nr(const char *syscall_name)
923{
924 int syscall_nr = -1;
925 int i;
926
927 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
928 const struct trace_syscall_entry *entry;
5b7ac358 929 const char *it_name;
80f87dd2
MD
930
931 entry = &sc_table[i];
932 if (!entry->desc)
933 continue;
5b7ac358
MD
934 it_name = entry->desc->name;
935 it_name += strlen(SYSCALL_ENTRY_STR);
936 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
937 syscall_nr = i;
938 break;
939 }
940 }
941 return syscall_nr;
942}
943
944static
945int get_compat_syscall_nr(const char *syscall_name)
946{
947 int syscall_nr = -1;
948 int i;
949
950 for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++) {
951 const struct trace_syscall_entry *entry;
5b7ac358 952 const char *it_name;
80f87dd2
MD
953
954 entry = &compat_sc_table[i];
955 if (!entry->desc)
956 continue;
5b7ac358
MD
957 it_name = entry->desc->name;
958 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
959 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
960 syscall_nr = i;
961 break;
962 }
963 }
964 return syscall_nr;
965}
966
12e579db
MD
967static
968uint32_t get_sc_tables_len(void)
969{
970 return ARRAY_SIZE(sc_table) + ARRAY_SIZE(compat_sc_table);
971}
972
80f87dd2
MD
973int lttng_syscall_filter_enable(struct lttng_channel *chan,
974 const char *name)
975{
976 int syscall_nr, compat_syscall_nr, ret;
977 struct lttng_syscall_filter *filter;
978
979 WARN_ON_ONCE(!chan->sc_table);
980
981 if (!name) {
982 /* Enable all system calls by removing filter */
983 if (chan->sc_filter) {
984 filter = chan->sc_filter;
985 rcu_assign_pointer(chan->sc_filter, NULL);
986 synchronize_trace();
987 kfree(filter);
988 }
989 chan->syscall_all = 1;
990 return 0;
991 }
992
993 if (!chan->sc_filter) {
994 if (chan->syscall_all) {
995 /*
996 * All syscalls are already enabled.
997 */
998 return -EEXIST;
999 }
1000 filter = kzalloc(sizeof(struct lttng_syscall_filter),
1001 GFP_KERNEL);
1002 if (!filter)
1003 return -ENOMEM;
1004 } else {
1005 filter = chan->sc_filter;
1006 }
1007 syscall_nr = get_syscall_nr(name);
1008 compat_syscall_nr = get_compat_syscall_nr(name);
1009 if (syscall_nr < 0 && compat_syscall_nr < 0) {
1010 ret = -ENOENT;
1011 goto error;
1012 }
1013 if (syscall_nr >= 0) {
1014 if (test_bit(syscall_nr, filter->sc)) {
1015 ret = -EEXIST;
1016 goto error;
1017 }
1018 bitmap_set(filter->sc, syscall_nr, 1);
1019 }
1020 if (compat_syscall_nr >= 0) {
1021 if (test_bit(compat_syscall_nr, filter->sc_compat)) {
1022 ret = -EEXIST;
1023 goto error;
1024 }
1025 bitmap_set(filter->sc_compat, compat_syscall_nr, 1);
1026 }
1027 if (!chan->sc_filter)
1028 rcu_assign_pointer(chan->sc_filter, filter);
1029 return 0;
1030
1031error:
1032 if (!chan->sc_filter)
1033 kfree(filter);
1034 return ret;
1035}
1036
1037int lttng_syscall_filter_disable(struct lttng_channel *chan,
1038 const char *name)
1039{
1040 int syscall_nr, compat_syscall_nr, ret;
1041 struct lttng_syscall_filter *filter;
1042
1043 WARN_ON_ONCE(!chan->sc_table);
1044
1045 if (!chan->sc_filter) {
bcde0d5b
MD
1046 if (!chan->syscall_all)
1047 return -EEXIST;
80f87dd2
MD
1048 filter = kzalloc(sizeof(struct lttng_syscall_filter),
1049 GFP_KERNEL);
1050 if (!filter)
1051 return -ENOMEM;
1052 /* Trace all system calls, then apply disable. */
1053 bitmap_set(filter->sc, 0, NR_syscalls);
1054 bitmap_set(filter->sc_compat, 0, NR_compat_syscalls);
1055 } else {
1056 filter = chan->sc_filter;
1057 }
1058
72814741 1059 if (!name) {
404e87bf
MD
1060 /* Fail if all syscalls are already disabled. */
1061 if (bitmap_empty(filter->sc, NR_syscalls)
1062 && bitmap_empty(filter->sc_compat,
1063 NR_compat_syscalls)) {
1064 ret = -EEXIST;
1065 goto error;
1066 }
1067
72814741
MD
1068 /* Disable all system calls */
1069 bitmap_clear(filter->sc, 0, NR_syscalls);
1070 bitmap_clear(filter->sc_compat, 0, NR_compat_syscalls);
1071 goto apply_filter;
1072 }
80f87dd2
MD
1073 syscall_nr = get_syscall_nr(name);
1074 compat_syscall_nr = get_compat_syscall_nr(name);
1075 if (syscall_nr < 0 && compat_syscall_nr < 0) {
1076 ret = -ENOENT;
1077 goto error;
1078 }
1079 if (syscall_nr >= 0) {
cecef7f8 1080 if (!test_bit(syscall_nr, filter->sc)) {
80f87dd2
MD
1081 ret = -EEXIST;
1082 goto error;
1083 }
cecef7f8 1084 bitmap_clear(filter->sc, syscall_nr, 1);
80f87dd2
MD
1085 }
1086 if (compat_syscall_nr >= 0) {
cecef7f8 1087 if (!test_bit(compat_syscall_nr, filter->sc_compat)) {
80f87dd2
MD
1088 ret = -EEXIST;
1089 goto error;
1090 }
cecef7f8 1091 bitmap_clear(filter->sc_compat, compat_syscall_nr, 1);
80f87dd2 1092 }
72814741 1093apply_filter:
80f87dd2
MD
1094 if (!chan->sc_filter)
1095 rcu_assign_pointer(chan->sc_filter, filter);
1096 chan->syscall_all = 0;
259b6cb3 1097 return 0;
80f87dd2
MD
1098
1099error:
1100 if (!chan->sc_filter)
1101 kfree(filter);
1102 return ret;
259b6cb3 1103}
2d2464bd
MD
1104
1105static
1106const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
1107{
1108 const struct trace_syscall_entry *entry;
1109 int iter = 0;
1110
1111 for (entry = sc_table;
1112 entry < sc_table + ARRAY_SIZE(sc_table);
1113 entry++) {
1114 if (iter++ >= *pos)
1115 return entry;
1116 }
1117 for (entry = compat_sc_table;
1118 entry < compat_sc_table + ARRAY_SIZE(compat_sc_table);
1119 entry++) {
1120 if (iter++ >= *pos)
1121 return entry;
1122 }
1123 /* End of list */
1124 return NULL;
1125}
1126
1127static
1128void *syscall_list_start(struct seq_file *m, loff_t *pos)
1129{
1130 return (void *) syscall_list_get_entry(pos);
1131}
1132
1133static
1134void *syscall_list_next(struct seq_file *m, void *p, loff_t *ppos)
1135{
1136 (*ppos)++;
1137 return (void *) syscall_list_get_entry(ppos);
1138}
1139
1140static
1141void syscall_list_stop(struct seq_file *m, void *p)
1142{
1143}
1144
12e579db
MD
1145static
1146int get_sc_table(const struct trace_syscall_entry *entry,
1147 const struct trace_syscall_entry **table,
1148 unsigned int *bitness)
1149{
1150 if (entry >= sc_table && entry < sc_table + ARRAY_SIZE(sc_table)) {
1151 if (bitness)
1152 *bitness = BITS_PER_LONG;
1153 if (table)
1154 *table = sc_table;
1155 return 0;
1156 }
1157 if (!(entry >= compat_sc_table
1158 && entry < compat_sc_table + ARRAY_SIZE(compat_sc_table))) {
1159 return -EINVAL;
1160 }
1161 if (bitness)
1162 *bitness = 32;
1163 if (table)
1164 *table = compat_sc_table;
1165 return 0;
1166}
1167
2d2464bd
MD
1168static
1169int syscall_list_show(struct seq_file *m, void *p)
1170{
1171 const struct trace_syscall_entry *table, *entry = p;
1172 unsigned int bitness;
d4291869 1173 unsigned long index;
12e579db 1174 int ret;
d4291869 1175 const char *name;
2d2464bd 1176
12e579db
MD
1177 ret = get_sc_table(entry, &table, &bitness);
1178 if (ret)
1179 return ret;
f4855b46
MD
1180 if (!entry->desc)
1181 return 0;
d4291869
MD
1182 if (table == sc_table) {
1183 index = entry - table;
1184 name = &entry->desc->name[strlen(SYSCALL_ENTRY_STR)];
1185 } else {
1186 index = (entry - table) + ARRAY_SIZE(sc_table);
1187 name = &entry->desc->name[strlen(COMPAT_SYSCALL_ENTRY_STR)];
1188 }
12e579db 1189 seq_printf(m, "syscall { index = %lu; name = %s; bitness = %u; };\n",
d4291869 1190 index, name, bitness);
2d2464bd
MD
1191 return 0;
1192}
1193
1194static
1195const struct seq_operations lttng_syscall_list_seq_ops = {
1196 .start = syscall_list_start,
1197 .next = syscall_list_next,
1198 .stop = syscall_list_stop,
1199 .show = syscall_list_show,
1200};
1201
1202static
1203int lttng_syscall_list_open(struct inode *inode, struct file *file)
1204{
1205 return seq_open(file, &lttng_syscall_list_seq_ops);
1206}
1207
1208const struct file_operations lttng_syscall_list_fops = {
1209 .owner = THIS_MODULE,
1210 .open = lttng_syscall_list_open,
1211 .read = seq_read,
1212 .llseek = seq_lseek,
1213 .release = seq_release,
1214};
12e579db
MD
1215
1216long lttng_channel_syscall_mask(struct lttng_channel *channel,
1217 struct lttng_kernel_syscall_mask __user *usyscall_mask)
1218{
1219 uint32_t len, sc_tables_len, bitmask_len;
1220 int ret = 0, bit;
1221 char *tmp_mask;
1222 struct lttng_syscall_filter *filter;
1223
1224 ret = get_user(len, &usyscall_mask->len);
1225 if (ret)
1226 return ret;
1227 sc_tables_len = get_sc_tables_len();
1228 bitmask_len = ALIGN(sc_tables_len, 8) >> 3;
1229 if (len < sc_tables_len) {
1230 return put_user(sc_tables_len, &usyscall_mask->len);
1231 }
1232 /* Array is large enough, we can copy array to user-space. */
1233 tmp_mask = kzalloc(bitmask_len, GFP_KERNEL);
1234 if (!tmp_mask)
1235 return -ENOMEM;
1236 filter = channel->sc_filter;
1237
1238 for (bit = 0; bit < ARRAY_SIZE(sc_table); bit++) {
2f25059d
MD
1239 bool state;
1240
1241 if (channel->sc_table) {
1242 if (filter)
1243 state = test_bit(bit, filter->sc);
1244 else
1245 state = 1;
1246 } else {
1247 state = 0;
1248 }
1249 bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
12e579db
MD
1250 }
1251 for (; bit < sc_tables_len; bit++) {
2f25059d
MD
1252 bool state;
1253
1254 if (channel->compat_sc_table) {
1255 if (filter)
1256 state = test_bit(bit - ARRAY_SIZE(sc_table),
1257 filter->sc_compat);
1258 else
1259 state = 1;
1260 } else {
1261 state = 0;
1262 }
1263 bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
12e579db
MD
1264 }
1265 if (copy_to_user(usyscall_mask->mask, tmp_mask, bitmask_len))
1266 ret = -EFAULT;
1267 kfree(tmp_mask);
1268 return ret;
1269}
082d4946
MD
1270
1271int lttng_abi_syscall_list(void)
1272{
1273 struct file *syscall_list_file;
1274 int file_fd, ret;
1275
4ac10b76 1276 file_fd = lttng_get_unused_fd();
082d4946
MD
1277 if (file_fd < 0) {
1278 ret = file_fd;
1279 goto fd_error;
1280 }
1281
1282 syscall_list_file = anon_inode_getfile("[lttng_syscall_list]",
1283 &lttng_syscall_list_fops,
1284 NULL, O_RDWR);
1285 if (IS_ERR(syscall_list_file)) {
1286 ret = PTR_ERR(syscall_list_file);
1287 goto file_error;
1288 }
1289 ret = lttng_syscall_list_fops.open(NULL, syscall_list_file);
1290 if (ret < 0)
1291 goto open_error;
1292 fd_install(file_fd, syscall_list_file);
1293 if (file_fd < 0) {
1294 ret = file_fd;
1295 goto fd_error;
1296 }
1297 return file_fd;
1298
1299open_error:
1300 fput(syscall_list_file);
1301file_error:
1302 put_unused_fd(file_fd);
1303fd_error:
1304 return ret;
1305}
This page took 0.092746 seconds and 4 git commands to generate.