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