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