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