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