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