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