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