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