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