Extract input/output arguments from accept and connect syscalls
[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
f7bdf4db
MD
75/*
76 * Take care of NOARGS not supported by mainline.
77 */
78#define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
79#define DEFINE_EVENT_NOARGS(template, name)
80#define TRACE_EVENT_NOARGS(name, struct, assign, print)
81
259b6cb3
MD
82/*
83 * Create LTTng tracepoint probes.
84 */
85#define LTTNG_PACKAGE_BUILD
86#define CREATE_TRACE_POINTS
2655f9ad 87#define TP_MODULE_NOINIT
2f804c0a 88#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
259b6cb3 89
a93244f8
MD
90#define PARAMS(args...) args
91
5b7ac358
MD
92/* Handle unknown syscalls */
93#define TRACE_SYSTEM syscalls_unknown
94#include "instrumentation/syscalls/headers/syscalls_unknown.h"
95#undef TRACE_SYSTEM
96
fc4f7161
MD
97#define SC_ENTER
98
fc4f7161
MD
99#undef sc_exit
100#define sc_exit(...)
b75d00c4
MD
101#undef sc_in
102#define sc_in(...) __VA_ARGS__
103#undef sc_out
104#define sc_out(...)
105#undef sc_inout
106#define sc_inout(...) __VA_ARGS__
5b7ac358
MD
107
108/* Hijack probe callback for system call enter */
a93244f8 109#undef TP_PROBE_CB
259b6cb3 110#define TP_PROBE_CB(_template) &syscall_entry_probe
a93244f8 111#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 112 TRACE_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
a93244f8 113 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
7ca580f8
MD
114#define SC_LTTNG_TRACE_EVENT(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
115 LTTNG_TRACE_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
116 PARAMS(_locvar), PARAMS(_code),\
117 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
a93244f8 118#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358 119 DECLARE_EVENT_CLASS_NOARGS(syscall_enter_##_name, PARAMS(_struct), PARAMS(_assign),\
a93244f8
MD
120 PARAMS(_printk))
121#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358 122 DEFINE_EVENT_NOARGS(syscall_enter_##_template, syscall_enter_##_name)
a93244f8 123#undef TRACE_SYSTEM
5b7ac358
MD
124#define TRACE_SYSTEM syscall_enter_integers
125#define TRACE_INCLUDE_FILE syscalls_integers
177b3692 126#include "instrumentation/syscalls/headers/syscalls_integers.h"
5b7ac358 127#undef TRACE_INCLUDE_FILE
a93244f8 128#undef TRACE_SYSTEM
5b7ac358
MD
129#define TRACE_SYSTEM syscall_enter_pointers
130#define TRACE_INCLUDE_FILE syscalls_pointers
177b3692 131#include "instrumentation/syscalls/headers/syscalls_pointers.h"
5b7ac358 132#undef TRACE_INCLUDE_FILE
a93244f8 133#undef TRACE_SYSTEM
7ca580f8 134#undef SC_LTTNG_TRACE_EVENT
a93244f8
MD
135#undef SC_TRACE_EVENT
136#undef SC_DECLARE_EVENT_CLASS_NOARGS
137#undef SC_DEFINE_EVENT_NOARGS
5b7ac358 138#undef TP_PROBE_CB
a93244f8
MD
139#undef _TRACE_SYSCALLS_integers_H
140#undef _TRACE_SYSCALLS_pointers_H
141
5b7ac358
MD
142
143/* Hijack probe callback for compat system call enter */
a93244f8
MD
144#define TP_PROBE_CB(_template) &syscall_entry_probe
145#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 146 TRACE_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
a93244f8
MD
147 PARAMS(_struct), PARAMS(_assign), \
148 PARAMS(_printk))
7ca580f8
MD
149#define SC_LTTNG_TRACE_EVENT(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
150 LTTNG_TRACE_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
151 PARAMS(_locvar), PARAMS(_code),\
152 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
a93244f8 153#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358
MD
154 DECLARE_EVENT_CLASS_NOARGS(compat_syscall_enter_##_name, PARAMS(_struct), \
155 PARAMS(_assign), PARAMS(_printk))
156#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
157 DEFINE_EVENT_NOARGS(compat_syscall_enter_##_template, \
158 compat_syscall_enter_##_name)
159#define TRACE_SYSTEM compat_syscall_enter_integers
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
164#define TRACE_SYSTEM compat_syscall_enter_pointers
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
7ca580f8 169#undef SC_LTTNG_TRACE_EVENT
5b7ac358
MD
170#undef SC_TRACE_EVENT
171#undef SC_DECLARE_EVENT_CLASS_NOARGS
172#undef SC_DEFINE_EVENT_NOARGS
173#undef TP_PROBE_CB
174#undef _TRACE_SYSCALLS_integers_H
175#undef _TRACE_SYSCALLS_pointers_H
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
192#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
193 TRACE_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args),\
194 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
7ca580f8
MD
195#define SC_LTTNG_TRACE_EVENT(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
196 LTTNG_TRACE_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args),\
197 PARAMS(_locvar), PARAMS(_code),\
198 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
5b7ac358
MD
199#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
200 DECLARE_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_struct), \
201 PARAMS(_assign), PARAMS(_printk))
202#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
203 DEFINE_EVENT_NOARGS(syscall_exit_##_template, \
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
7ca580f8 215#undef SC_LTTNG_TRACE_EVENT
5b7ac358
MD
216#undef SC_TRACE_EVENT
217#undef SC_DECLARE_EVENT_CLASS_NOARGS
218#undef SC_DEFINE_EVENT_NOARGS
219#undef TP_PROBE_CB
220#undef _TRACE_SYSCALLS_integers_H
221#undef _TRACE_SYSCALLS_pointers_H
222
223
224/* Hijack probe callback for compat system call exit */
225#define TP_PROBE_CB(_template) &syscall_exit_probe
226#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
227 TRACE_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
228 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
7ca580f8
MD
229#define SC_LTTNG_TRACE_EVENT(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
230 LTTNG_TRACE_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args),\
231 PARAMS(_locvar), PARAMS(_code),\
232 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
5b7ac358
MD
233#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
234 DECLARE_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_struct), \
a93244f8
MD
235 PARAMS(_assign), PARAMS(_printk))
236#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358
MD
237 DEFINE_EVENT_NOARGS(compat_syscall_exit_##_template, \
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
7ca580f8 249#undef SC_LTTNG_TRACE_EVENT
a93244f8
MD
250#undef SC_TRACE_EVENT
251#undef SC_DECLARE_EVENT_CLASS_NOARGS
252#undef SC_DEFINE_EVENT_NOARGS
253#undef TP_PROBE_CB
5b7ac358
MD
254#undef _TRACE_SYSCALLS_integers_H
255#undef _TRACE_SYSCALLS_pointers_H
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 ] = { \
5b7ac358 280 .func = __event_probe__syscall_enter_##_template, \
259b6cb3 281 .nrargs = (_nrargs), \
5b7ac358
MD
282 .fields = __event_fields___syscall_enter_##_template, \
283 .desc = &__event_desc___syscall_enter_##_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 ] = { \
5b7ac358 295 .func = __event_probe__compat_syscall_enter_##_template, \
a93244f8 296 .nrargs = (_nrargs), \
5b7ac358
MD
297 .fields = __event_fields___compat_syscall_enter_##_template, \
298 .desc = &__event_desc___compat_syscall_enter_##_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()))
5b7ac358 360 __event_probe__compat_syscall_enter_unknown(event, id, args);
a93244f8 361 else
5b7ac358 362 __event_probe__syscall_enter_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 =
5b7ac358 773 &__event_desc___syscall_enter_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 =
5b7ac358 789 &__event_desc___compat_syscall_enter_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
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
1044 syscall_nr = get_syscall_nr(name);
1045 compat_syscall_nr = get_compat_syscall_nr(name);
1046 if (syscall_nr < 0 && compat_syscall_nr < 0) {
1047 ret = -ENOENT;
1048 goto error;
1049 }
1050 if (syscall_nr >= 0) {
1051 if (!test_bit(syscall_nr, chan->sc_filter->sc)) {
1052 ret = -EEXIST;
1053 goto error;
1054 }
1055 bitmap_clear(chan->sc_filter->sc, syscall_nr, 1);
1056 }
1057 if (compat_syscall_nr >= 0) {
1058 if (!test_bit(compat_syscall_nr, chan->sc_filter->sc_compat)) {
1059 ret = -EEXIST;
1060 goto error;
1061 }
1062 bitmap_clear(chan->sc_filter->sc_compat, compat_syscall_nr, 1);
1063 }
1064 if (!chan->sc_filter)
1065 rcu_assign_pointer(chan->sc_filter, filter);
1066 chan->syscall_all = 0;
259b6cb3 1067 return 0;
80f87dd2
MD
1068
1069error:
1070 if (!chan->sc_filter)
1071 kfree(filter);
1072 return ret;
259b6cb3 1073}
This page took 0.0748760000000001 seconds and 4 git commands to generate.