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