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