Fix: MODULE_IMPORT_NS is introduced in kernel 5.4
[lttng-modules.git] / src / lttng-syscalls.c
1 /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
2 *
3 * lttng-syscalls.c
4 *
5 * LTTng syscall probes.
6 *
7 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 */
9
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/compat.h>
13 #include <linux/err.h>
14 #include <linux/bitmap.h>
15 #include <linux/in.h>
16 #include <linux/in6.h>
17 #include <linux/seq_file.h>
18 #include <linux/stringify.h>
19 #include <linux/file.h>
20 #include <linux/anon_inodes.h>
21 #include <linux/fcntl.h>
22 #include <linux/mman.h>
23 #include <asm/ptrace.h>
24 #include <asm/syscall.h>
25
26 #include <lttng/bitfield.h>
27 #include <wrapper/tracepoint.h>
28 #include <wrapper/file.h>
29 #include <wrapper/rcu.h>
30 #include <wrapper/syscall.h>
31 #include <wrapper/limits.h>
32 #include <lttng/events.h>
33 #include <lttng/events-internal.h>
34 #include <lttng/utils.h>
35 #include <lttng/kernel-version.h>
36
37 #include "lttng-syscalls.h"
38
39 #ifndef CONFIG_COMPAT
40 # ifndef is_compat_task
41 # define is_compat_task() (0)
42 # endif
43 #endif
44
45 /* in_compat_syscall appears in kernel 4.6. */
46 #ifndef in_compat_syscall
47 # define in_compat_syscall() is_compat_task()
48 #endif
49
50 /* in_x32_syscall appears in kernel 4.7. */
51 #if (LTTNG_LINUX_VERSION_CODE < LTTNG_KERNEL_VERSION(4,7,0))
52 # ifdef CONFIG_X86_X32_ABI
53 # define in_x32_syscall() is_x32_task()
54 # endif
55 #endif
56
57 enum sc_type {
58 SC_TYPE_ENTRY,
59 SC_TYPE_EXIT,
60 SC_TYPE_COMPAT_ENTRY,
61 SC_TYPE_COMPAT_EXIT,
62 };
63
64 #define SYSCALL_ENTRY_TOK syscall_entry_
65 #define COMPAT_SYSCALL_ENTRY_TOK compat_syscall_entry_
66 #define SYSCALL_EXIT_TOK syscall_exit_
67 #define COMPAT_SYSCALL_EXIT_TOK compat_syscall_exit_
68
69 #define SYSCALL_ENTRY_STR __stringify(SYSCALL_ENTRY_TOK)
70 #define COMPAT_SYSCALL_ENTRY_STR __stringify(COMPAT_SYSCALL_ENTRY_TOK)
71 #define SYSCALL_EXIT_STR __stringify(SYSCALL_EXIT_TOK)
72 #define COMPAT_SYSCALL_EXIT_STR __stringify(COMPAT_SYSCALL_EXIT_TOK)
73
74 void syscall_entry_event_probe(void *__data, struct pt_regs *regs, long id);
75 void syscall_exit_event_probe(void *__data, struct pt_regs *regs, long ret);
76
77 void syscall_entry_event_notifier_probe(void *__data, struct pt_regs *regs,
78 long id);
79 void syscall_exit_event_notifier_probe(void *__data, struct pt_regs *regs,
80 long ret);
81
82 /*
83 * Forward declarations for old kernels.
84 */
85 struct mmsghdr;
86 struct rlimit64;
87 struct oldold_utsname;
88 struct old_utsname;
89 struct sel_arg_struct;
90 struct mmap_arg_struct;
91 struct file_handle;
92 struct user_msghdr;
93
94 /*
95 * Forward declaration for kernels >= 5.6
96 */
97 struct timex;
98 struct timeval;
99 struct itimerval;
100 struct itimerspec;
101
102 #if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,6,0))
103 typedef __kernel_old_time_t time_t;
104 #endif
105
106 #ifdef IA32_NR_syscalls
107 #define NR_compat_syscalls IA32_NR_syscalls
108 #else
109 #define NR_compat_syscalls NR_syscalls
110 #endif
111
112 /*
113 * Create LTTng tracepoint probes.
114 */
115 #define LTTNG_PACKAGE_BUILD
116 #define CREATE_TRACE_POINTS
117 #define TP_MODULE_NOINIT
118 #define TRACE_INCLUDE_PATH instrumentation/syscalls/headers
119
120 #define PARAMS(args...) args
121
122 /* Handle unknown syscalls */
123 #undef TRACE_SYSTEM
124 #define TRACE_SYSTEM syscalls_unknown
125 #include <instrumentation/syscalls/headers/syscalls_unknown.h>
126 #undef TRACE_SYSTEM
127
128 #undef TP_PROBE_CB
129
130 extern const struct trace_syscall_table sc_table;
131 extern const struct trace_syscall_table compat_sc_table;
132
133 /* Event syscall exit table */
134 extern const struct trace_syscall_table sc_exit_table;
135 extern const struct trace_syscall_table compat_sc_exit_table;
136
137
138 #undef SC_EXIT
139
140 #undef CREATE_SYSCALL_TABLE
141
142 struct lttng_syscall_filter {
143 DECLARE_BITMAP(sc_entry, NR_syscalls);
144 DECLARE_BITMAP(sc_exit, NR_syscalls);
145 DECLARE_BITMAP(sc_compat_entry, NR_compat_syscalls);
146 DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls);
147
148 /*
149 * Reference counters keeping track of number of events enabled
150 * for each bit.
151 */
152 u32 sc_entry_refcount_map[NR_syscalls];
153 u32 sc_exit_refcount_map[NR_syscalls];
154 u32 sc_compat_entry_refcount_map[NR_compat_syscalls];
155 u32 sc_compat_exit_refcount_map[NR_compat_syscalls];
156 };
157
158 static void syscall_entry_event_unknown(struct hlist_head *unknown_action_list_head,
159 struct pt_regs *regs, long id)
160 {
161 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
162 struct lttng_kernel_event_common_private *event_priv;
163
164 lttng_syscall_get_arguments(current, regs, args);
165 lttng_hlist_for_each_entry_rcu(event_priv, unknown_action_list_head, u.syscall.node) {
166 if (unlikely(in_compat_syscall()))
167 __event_probe__compat_syscall_entry_unknown(event_priv->pub, id, args);
168 else
169 __event_probe__syscall_entry_unknown(event_priv->pub, id, args);
170 }
171 }
172
173 static __always_inline
174 void syscall_entry_event_call_func(struct hlist_head *action_list,
175 void *func, unsigned int nrargs,
176 struct pt_regs *regs)
177 {
178 struct lttng_kernel_event_common_private *event_priv;
179
180 switch (nrargs) {
181 case 0:
182 {
183 void (*fptr)(void *__data) = func;
184
185 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
186 fptr(event_priv->pub);
187 break;
188 }
189 case 1:
190 {
191 void (*fptr)(void *__data, unsigned long arg0) = func;
192 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
193
194 lttng_syscall_get_arguments(current, regs, args);
195 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
196 fptr(event_priv->pub, args[0]);
197 break;
198 }
199 case 2:
200 {
201 void (*fptr)(void *__data,
202 unsigned long arg0,
203 unsigned long arg1) = func;
204 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
205
206 lttng_syscall_get_arguments(current, regs, args);
207 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
208 fptr(event_priv->pub, args[0], args[1]);
209 break;
210 }
211 case 3:
212 {
213 void (*fptr)(void *__data,
214 unsigned long arg0,
215 unsigned long arg1,
216 unsigned long arg2) = func;
217 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
218
219 lttng_syscall_get_arguments(current, regs, args);
220 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
221 fptr(event_priv->pub, args[0], args[1], args[2]);
222 break;
223 }
224 case 4:
225 {
226 void (*fptr)(void *__data,
227 unsigned long arg0,
228 unsigned long arg1,
229 unsigned long arg2,
230 unsigned long arg3) = func;
231 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
232
233 lttng_syscall_get_arguments(current, regs, args);
234 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
235 fptr(event_priv->pub, args[0], args[1], args[2], args[3]);
236 break;
237 }
238 case 5:
239 {
240 void (*fptr)(void *__data,
241 unsigned long arg0,
242 unsigned long arg1,
243 unsigned long arg2,
244 unsigned long arg3,
245 unsigned long arg4) = func;
246 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
247
248 lttng_syscall_get_arguments(current, regs, args);
249 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
250 fptr(event_priv->pub, args[0], args[1], args[2], args[3], args[4]);
251 break;
252 }
253 case 6:
254 {
255 void (*fptr)(void *__data,
256 unsigned long arg0,
257 unsigned long arg1,
258 unsigned long arg2,
259 unsigned long arg3,
260 unsigned long arg4,
261 unsigned long arg5) = func;
262 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
263
264 lttng_syscall_get_arguments(current, regs, args);
265 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
266 fptr(event_priv->pub, args[0], args[1], args[2],
267 args[3], args[4], args[5]);
268 break;
269 }
270 default:
271 break;
272 }
273 }
274
275 void syscall_entry_event_probe(void *__data, struct pt_regs *regs, long id)
276 {
277 struct lttng_kernel_channel_buffer *chan = __data;
278 struct hlist_head *action_list, *unknown_action_list;
279 const struct trace_syscall_entry *table, *entry;
280 size_t table_len;
281
282 #ifdef CONFIG_X86_X32_ABI
283 if (in_x32_syscall()) {
284 /* x32 system calls are not supported. */
285 return;
286 }
287 #endif
288 if (unlikely(in_compat_syscall())) {
289 struct lttng_syscall_filter *filter = chan->priv->parent.sc_filter;
290
291 if (id < 0 || id >= NR_compat_syscalls
292 || (!READ_ONCE(chan->priv->parent.syscall_all_entry) && !test_bit(id, filter->sc_compat_entry))) {
293 /* System call filtered out. */
294 return;
295 }
296 table = compat_sc_table.table;
297 table_len = compat_sc_table.len;
298 unknown_action_list = &chan->priv->parent.sc_compat_unknown;
299 } else {
300 struct lttng_syscall_filter *filter = chan->priv->parent.sc_filter;
301
302 if (id < 0 || id >= NR_syscalls
303 || (!READ_ONCE(chan->priv->parent.syscall_all_entry) && !test_bit(id, filter->sc_entry))) {
304 /* System call filtered out. */
305 return;
306 }
307 table = sc_table.table;
308 table_len = sc_table.len;
309 unknown_action_list = &chan->priv->parent.sc_unknown;
310 }
311 if (unlikely(id < 0 || id >= table_len)) {
312 syscall_entry_event_unknown(unknown_action_list, regs, id);
313 return;
314 }
315
316 entry = &table[id];
317 if (!entry->event_func) {
318 syscall_entry_event_unknown(unknown_action_list, regs, id);
319 return;
320 }
321
322 if (unlikely(in_compat_syscall())) {
323 action_list = &chan->priv->parent.compat_sc_table[id];
324 } else {
325 action_list = &chan->priv->parent.sc_table[id];
326 }
327 if (unlikely(hlist_empty(action_list)))
328 return;
329
330 syscall_entry_event_call_func(action_list, entry->event_func, entry->nrargs, regs);
331 }
332
333 void syscall_entry_event_notifier_probe(void *__data, struct pt_regs *regs,
334 long id)
335 {
336 struct lttng_event_notifier_group *group = __data;
337 const struct trace_syscall_entry *table, *entry;
338 struct hlist_head *dispatch_list, *unknown_dispatch_list;
339 size_t table_len;
340
341 if (unlikely(in_compat_syscall())) {
342 struct lttng_syscall_filter *filter = group->sc_filter;
343
344 if (id < 0 || id >= NR_compat_syscalls
345 || (!READ_ONCE(group->syscall_all_entry) &&
346 !test_bit(id, filter->sc_compat_entry))) {
347 /* System call filtered out. */
348 return;
349 }
350 table = compat_sc_table.table;
351 table_len = compat_sc_table.len;
352 unknown_dispatch_list = &group->event_notifier_compat_unknown_syscall_dispatch;
353 } else {
354 struct lttng_syscall_filter *filter = group->sc_filter;
355
356 if (id < 0 || id >= NR_syscalls
357 || (!READ_ONCE(group->syscall_all_entry) &&
358 !test_bit(id, filter->sc_entry))) {
359 /* System call filtered out. */
360 return;
361 }
362 table = sc_table.table;
363 table_len = sc_table.len;
364 unknown_dispatch_list = &group->event_notifier_unknown_syscall_dispatch;
365 }
366 /* Check if the syscall id is out of bound. */
367 if (unlikely(id < 0 || id >= table_len)) {
368 syscall_entry_event_unknown(unknown_dispatch_list,
369 regs, id);
370 return;
371 }
372
373 entry = &table[id];
374 if (!entry->event_func) {
375 syscall_entry_event_unknown(unknown_dispatch_list,
376 regs, id);
377 return;
378 }
379
380 if (unlikely(in_compat_syscall())) {
381 dispatch_list = &group->event_notifier_compat_syscall_dispatch[id];
382 } else {
383 dispatch_list = &group->event_notifier_syscall_dispatch[id];
384 }
385 if (unlikely(hlist_empty(dispatch_list)))
386 return;
387
388 syscall_entry_event_call_func(dispatch_list,
389 entry->event_func, entry->nrargs, regs);
390 }
391
392 static void syscall_exit_event_unknown(struct hlist_head *unknown_action_list_head,
393 struct pt_regs *regs, long id, long ret)
394 {
395 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
396 struct lttng_kernel_event_common_private *event_priv;
397
398 lttng_syscall_get_arguments(current, regs, args);
399 lttng_hlist_for_each_entry_rcu(event_priv, unknown_action_list_head, u.syscall.node) {
400 if (unlikely(in_compat_syscall()))
401 __event_probe__compat_syscall_exit_unknown(event_priv->pub, id, ret,
402 args);
403 else
404 __event_probe__syscall_exit_unknown(event_priv->pub, id, ret, args);
405 }
406 }
407
408 static __always_inline
409 void syscall_exit_event_call_func(struct hlist_head *action_list,
410 void *func, unsigned int nrargs,
411 struct pt_regs *regs, long ret)
412 {
413 struct lttng_kernel_event_common_private *event_priv;
414
415 switch (nrargs) {
416 case 0:
417 {
418 void (*fptr)(void *__data, long ret) = func;
419
420 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
421 fptr(event_priv->pub, ret);
422 break;
423 }
424 case 1:
425 {
426 void (*fptr)(void *__data,
427 long ret,
428 unsigned long arg0) = func;
429 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
430
431 lttng_syscall_get_arguments(current, regs, args);
432 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
433 fptr(event_priv->pub, ret, args[0]);
434 break;
435 }
436 case 2:
437 {
438 void (*fptr)(void *__data,
439 long ret,
440 unsigned long arg0,
441 unsigned long arg1) = func;
442 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
443
444 lttng_syscall_get_arguments(current, regs, args);
445 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
446 fptr(event_priv->pub, ret, args[0], args[1]);
447 break;
448 }
449 case 3:
450 {
451 void (*fptr)(void *__data,
452 long ret,
453 unsigned long arg0,
454 unsigned long arg1,
455 unsigned long arg2) = func;
456 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
457
458 lttng_syscall_get_arguments(current, regs, args);
459 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
460 fptr(event_priv->pub, ret, args[0], args[1], args[2]);
461 break;
462 }
463 case 4:
464 {
465 void (*fptr)(void *__data,
466 long ret,
467 unsigned long arg0,
468 unsigned long arg1,
469 unsigned long arg2,
470 unsigned long arg3) = func;
471 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
472
473 lttng_syscall_get_arguments(current, regs, args);
474 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
475 fptr(event_priv->pub, ret, args[0], args[1], args[2], args[3]);
476 break;
477 }
478 case 5:
479 {
480 void (*fptr)(void *__data,
481 long ret,
482 unsigned long arg0,
483 unsigned long arg1,
484 unsigned long arg2,
485 unsigned long arg3,
486 unsigned long arg4) = func;
487 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
488
489 lttng_syscall_get_arguments(current, regs, args);
490 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
491 fptr(event_priv->pub, ret, args[0], args[1], args[2], args[3], args[4]);
492 break;
493 }
494 case 6:
495 {
496 void (*fptr)(void *__data,
497 long ret,
498 unsigned long arg0,
499 unsigned long arg1,
500 unsigned long arg2,
501 unsigned long arg3,
502 unsigned long arg4,
503 unsigned long arg5) = func;
504 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
505
506 lttng_syscall_get_arguments(current, regs, args);
507 lttng_hlist_for_each_entry_rcu(event_priv, action_list, u.syscall.node)
508 fptr(event_priv->pub, ret, args[0], args[1], args[2],
509 args[3], args[4], args[5]);
510 break;
511 }
512 default:
513 break;
514 }
515 }
516
517 void syscall_exit_event_probe(void *__data, struct pt_regs *regs, long ret)
518 {
519 struct lttng_kernel_channel_buffer *chan = __data;
520 struct hlist_head *action_list, *unknown_action_list;
521 const struct trace_syscall_entry *table, *entry;
522 size_t table_len;
523 long id;
524
525 #ifdef CONFIG_X86_X32_ABI
526 if (in_x32_syscall()) {
527 /* x32 system calls are not supported. */
528 return;
529 }
530 #endif
531 id = syscall_get_nr(current, regs);
532
533 if (unlikely(in_compat_syscall())) {
534 struct lttng_syscall_filter *filter = chan->priv->parent.sc_filter;
535
536 if (id < 0 || id >= NR_compat_syscalls
537 || (!READ_ONCE(chan->priv->parent.syscall_all_exit) && !test_bit(id, filter->sc_compat_exit))) {
538 /* System call filtered out. */
539 return;
540 }
541 table = compat_sc_exit_table.table;
542 table_len = compat_sc_exit_table.len;
543 unknown_action_list = &chan->priv->parent.compat_sc_exit_unknown;
544 } else {
545 struct lttng_syscall_filter *filter = chan->priv->parent.sc_filter;
546
547 if (id < 0 || id >= NR_syscalls
548 || (!READ_ONCE(chan->priv->parent.syscall_all_exit) && !test_bit(id, filter->sc_exit))) {
549 /* System call filtered out. */
550 return;
551 }
552 table = sc_exit_table.table;
553 table_len = sc_exit_table.len;
554 unknown_action_list = &chan->priv->parent.sc_exit_unknown;
555 }
556 if (unlikely(id < 0 || id >= table_len)) {
557 syscall_exit_event_unknown(unknown_action_list, regs, id, ret);
558 return;
559 }
560
561 entry = &table[id];
562 if (!entry->event_func) {
563 syscall_exit_event_unknown(unknown_action_list, regs, id, ret);
564 return;
565 }
566
567 if (unlikely(in_compat_syscall())) {
568 action_list = &chan->priv->parent.compat_sc_exit_table[id];
569 } else {
570 action_list = &chan->priv->parent.sc_exit_table[id];
571 }
572 if (unlikely(hlist_empty(action_list)))
573 return;
574
575 syscall_exit_event_call_func(action_list, entry->event_func, entry->nrargs,
576 regs, ret);
577 }
578
579 void syscall_exit_event_notifier_probe(void *__data, struct pt_regs *regs,
580 long ret)
581 {
582 struct lttng_event_notifier_group *group = __data;
583 const struct trace_syscall_entry *table, *entry;
584 struct hlist_head *dispatch_list, *unknown_dispatch_list;
585 size_t table_len;
586 long id;
587
588 id = syscall_get_nr(current, regs);
589
590 if (unlikely(in_compat_syscall())) {
591 struct lttng_syscall_filter *filter = group->sc_filter;
592
593 if (id < 0 || id >= NR_compat_syscalls
594 || (!READ_ONCE(group->syscall_all_exit) &&
595 !test_bit(id, filter->sc_compat_exit))) {
596 /* System call filtered out. */
597 return;
598 }
599 table = compat_sc_exit_table.table;
600 table_len = compat_sc_exit_table.len;
601 unknown_dispatch_list = &group->event_notifier_exit_compat_unknown_syscall_dispatch;
602 } else {
603 struct lttng_syscall_filter *filter = group->sc_filter;
604
605 if (id < 0 || id >= NR_syscalls
606 || (!READ_ONCE(group->syscall_all_exit) &&
607 !test_bit(id, filter->sc_exit))) {
608 /* System call filtered out. */
609 return;
610 }
611 table = sc_exit_table.table;
612 table_len = sc_exit_table.len;
613 unknown_dispatch_list = &group->event_notifier_exit_unknown_syscall_dispatch;
614 }
615 /* Check if the syscall id is out of bound. */
616 if (unlikely(id < 0 || id >= table_len)) {
617 syscall_exit_event_unknown(unknown_dispatch_list,
618 regs, id, ret);
619 return;
620 }
621
622 entry = &table[id];
623 if (!entry->event_func) {
624 syscall_entry_event_unknown(unknown_dispatch_list,
625 regs, id);
626 return;
627 }
628
629 if (unlikely(in_compat_syscall())) {
630 dispatch_list = &group->event_notifier_exit_compat_syscall_dispatch[id];
631 } else {
632 dispatch_list = &group->event_notifier_exit_syscall_dispatch[id];
633 }
634 if (unlikely(hlist_empty(dispatch_list)))
635 return;
636
637 syscall_exit_event_call_func(dispatch_list,
638 entry->event_func, entry->nrargs, regs, ret);
639 }
640 /*
641 * noinline to diminish caller stack size.
642 * Should be called with sessions lock held.
643 */
644 static
645 int lttng_create_syscall_event_if_missing(const struct trace_syscall_entry *table, size_t table_len,
646 struct hlist_head *chan_table, struct lttng_event_enabler *event_enabler,
647 enum sc_type type)
648 {
649 struct lttng_kernel_channel_buffer *chan = event_enabler->chan;
650 struct lttng_kernel_session *session = chan->parent.session;
651 unsigned int i;
652
653 /* Allocate events for each syscall matching enabler, insert into table */
654 for (i = 0; i < table_len; i++) {
655 const struct lttng_kernel_event_desc *desc = table[i].desc;
656 struct lttng_kernel_abi_event ev;
657 struct lttng_kernel_event_recorder_private *event_recorder_priv;
658 struct lttng_kernel_event_recorder *event_recorder;
659 struct hlist_head *head;
660 bool found = false;
661
662 if (!desc) {
663 /* Unknown syscall */
664 continue;
665 }
666 if (lttng_desc_match_enabler(desc,
667 lttng_event_enabler_as_enabler(event_enabler)) <= 0)
668 continue;
669 /*
670 * Check if already created.
671 */
672 head = utils_borrow_hash_table_bucket(
673 session->priv->events_ht.table, LTTNG_EVENT_HT_SIZE,
674 desc->event_name);
675 lttng_hlist_for_each_entry(event_recorder_priv, head, hlist) {
676 if (event_recorder_priv->parent.desc == desc
677 && event_recorder_priv->pub->chan == event_enabler->chan)
678 found = true;
679 }
680 if (found)
681 continue;
682
683 /* We need to create an event for this syscall/enabler. */
684 memset(&ev, 0, sizeof(ev));
685 switch (type) {
686 case SC_TYPE_ENTRY:
687 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
688 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
689 break;
690 case SC_TYPE_EXIT:
691 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
692 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
693 break;
694 case SC_TYPE_COMPAT_ENTRY:
695 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
696 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
697 break;
698 case SC_TYPE_COMPAT_EXIT:
699 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
700 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
701 break;
702 }
703 strncpy(ev.name, desc->event_name, LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1);
704 ev.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
705 ev.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
706 event_recorder = _lttng_kernel_event_recorder_create(chan, &ev, desc, ev.instrumentation);
707 WARN_ON_ONCE(!event_recorder);
708 if (IS_ERR(event_recorder)) {
709 /*
710 * If something goes wrong in event registration
711 * after the first one, we have no choice but to
712 * leave the previous events in there, until
713 * deleted by session teardown.
714 */
715 return PTR_ERR(event_recorder);
716 }
717 hlist_add_head(&event_recorder->priv->parent.u.syscall.node, &chan_table[i]);
718 }
719 return 0;
720 }
721
722 /*
723 * Should be called with sessions lock held.
724 */
725 int lttng_syscalls_register_event(struct lttng_event_enabler *event_enabler)
726 {
727 struct lttng_kernel_channel_buffer *chan = event_enabler->chan;
728 struct lttng_kernel_abi_event ev;
729 int ret;
730
731 wrapper_vmalloc_sync_mappings();
732
733 if (!chan->priv->parent.sc_table) {
734 /* create syscall table mapping syscall to events */
735 chan->priv->parent.sc_table = kzalloc(sizeof(struct lttng_kernel_event_recorder *)
736 * sc_table.len, GFP_KERNEL);
737 if (!chan->priv->parent.sc_table)
738 return -ENOMEM;
739 }
740 if (!chan->priv->parent.sc_exit_table) {
741 /* create syscall table mapping syscall to events */
742 chan->priv->parent.sc_exit_table = kzalloc(sizeof(struct lttng_kernel_event_recorder *)
743 * sc_exit_table.len, GFP_KERNEL);
744 if (!chan->priv->parent.sc_exit_table)
745 return -ENOMEM;
746 }
747
748
749 #ifdef CONFIG_COMPAT
750 if (!chan->priv->parent.compat_sc_table) {
751 /* create syscall table mapping compat syscall to events */
752 chan->priv->parent.compat_sc_table = kzalloc(sizeof(struct lttng_kernel_event_recorder *)
753 * compat_sc_table.len, GFP_KERNEL);
754 if (!chan->priv->parent.compat_sc_table)
755 return -ENOMEM;
756 }
757
758 if (!chan->priv->parent.compat_sc_exit_table) {
759 /* create syscall table mapping compat syscall to events */
760 chan->priv->parent.compat_sc_exit_table = kzalloc(sizeof(struct lttng_kernel_event_recorder *)
761 * compat_sc_exit_table.len, GFP_KERNEL);
762 if (!chan->priv->parent.compat_sc_exit_table)
763 return -ENOMEM;
764 }
765 #endif
766 if (hlist_empty(&chan->priv->parent.sc_unknown)) {
767 const struct lttng_kernel_event_desc *desc =
768 &__event_desc___syscall_entry_unknown;
769 struct lttng_kernel_event_recorder *event_recorder;
770
771 memset(&ev, 0, sizeof(ev));
772 strncpy(ev.name, desc->event_name, LTTNG_KERNEL_ABI_SYM_NAME_LEN);
773 ev.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
774 ev.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
775 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
776 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
777 event_recorder = _lttng_kernel_event_recorder_create(chan, &ev, desc,
778 ev.instrumentation);
779 WARN_ON_ONCE(!event_recorder);
780 if (IS_ERR(event_recorder)) {
781 return PTR_ERR(event_recorder);
782 }
783 hlist_add_head(&event_recorder->priv->parent.u.syscall.node, &chan->priv->parent.sc_unknown);
784 }
785
786 if (hlist_empty(&chan->priv->parent.sc_compat_unknown)) {
787 const struct lttng_kernel_event_desc *desc =
788 &__event_desc___compat_syscall_entry_unknown;
789 struct lttng_kernel_event_recorder *event_recorder;
790
791 memset(&ev, 0, sizeof(ev));
792 strncpy(ev.name, desc->event_name, LTTNG_KERNEL_ABI_SYM_NAME_LEN);
793 ev.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
794 ev.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
795 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
796 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
797 event_recorder = _lttng_kernel_event_recorder_create(chan, &ev, desc,
798 ev.instrumentation);
799 WARN_ON_ONCE(!event_recorder);
800 if (IS_ERR(event_recorder)) {
801 return PTR_ERR(event_recorder);
802 }
803 hlist_add_head(&event_recorder->priv->parent.u.syscall.node, &chan->priv->parent.sc_compat_unknown);
804 }
805
806 if (hlist_empty(&chan->priv->parent.compat_sc_exit_unknown)) {
807 const struct lttng_kernel_event_desc *desc =
808 &__event_desc___compat_syscall_exit_unknown;
809 struct lttng_kernel_event_recorder *event_recorder;
810
811 memset(&ev, 0, sizeof(ev));
812 strncpy(ev.name, desc->event_name, LTTNG_KERNEL_ABI_SYM_NAME_LEN);
813 ev.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
814 ev.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
815 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
816 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
817 event_recorder = _lttng_kernel_event_recorder_create(chan, &ev, desc,
818 ev.instrumentation);
819 WARN_ON_ONCE(!event_recorder);
820 if (IS_ERR(event_recorder)) {
821 return PTR_ERR(event_recorder);
822 }
823 hlist_add_head(&event_recorder->priv->parent.u.syscall.node, &chan->priv->parent.compat_sc_exit_unknown);
824 }
825
826 if (hlist_empty(&chan->priv->parent.sc_exit_unknown)) {
827 const struct lttng_kernel_event_desc *desc =
828 &__event_desc___syscall_exit_unknown;
829 struct lttng_kernel_event_recorder *event_recorder;
830
831 memset(&ev, 0, sizeof(ev));
832 strncpy(ev.name, desc->event_name, LTTNG_KERNEL_ABI_SYM_NAME_LEN);
833 ev.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
834 ev.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
835 ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
836 ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
837 event_recorder = _lttng_kernel_event_recorder_create(chan, &ev, desc,
838 ev.instrumentation);
839 WARN_ON_ONCE(!event_recorder);
840 if (IS_ERR(event_recorder)) {
841 return PTR_ERR(event_recorder);
842 }
843 hlist_add_head(&event_recorder->priv->parent.u.syscall.node, &chan->priv->parent.sc_exit_unknown);
844 }
845
846 ret = lttng_create_syscall_event_if_missing(sc_table.table, sc_table.len,
847 chan->priv->parent.sc_table, event_enabler, SC_TYPE_ENTRY);
848 if (ret)
849 return ret;
850 ret = lttng_create_syscall_event_if_missing(sc_exit_table.table, sc_exit_table.len,
851 chan->priv->parent.sc_exit_table, event_enabler, SC_TYPE_EXIT);
852 if (ret)
853 return ret;
854
855 #ifdef CONFIG_COMPAT
856 ret = lttng_create_syscall_event_if_missing(compat_sc_table.table, compat_sc_table.len,
857 chan->priv->parent.compat_sc_table, event_enabler, SC_TYPE_COMPAT_ENTRY);
858 if (ret)
859 return ret;
860 ret = lttng_create_syscall_event_if_missing(compat_sc_exit_table.table, compat_sc_exit_table.len,
861 chan->priv->parent.compat_sc_exit_table, event_enabler, SC_TYPE_COMPAT_EXIT);
862 if (ret)
863 return ret;
864 #endif
865
866 if (!chan->priv->parent.sc_filter) {
867 chan->priv->parent.sc_filter = kzalloc(sizeof(struct lttng_syscall_filter),
868 GFP_KERNEL);
869 if (!chan->priv->parent.sc_filter)
870 return -ENOMEM;
871 }
872
873 if (!chan->priv->parent.sys_enter_registered) {
874 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
875 (void *) syscall_entry_event_probe, chan);
876 if (ret)
877 return ret;
878 chan->priv->parent.sys_enter_registered = 1;
879 }
880 /*
881 * We change the name of sys_exit tracepoint due to namespace
882 * conflict with sys_exit syscall entry.
883 */
884 if (!chan->priv->parent.sys_exit_registered) {
885 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
886 (void *) syscall_exit_event_probe, chan);
887 if (ret) {
888 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
889 (void *) syscall_entry_event_probe, chan));
890 return ret;
891 }
892 chan->priv->parent.sys_exit_registered = 1;
893 }
894 return ret;
895 }
896
897 /*
898 * Should be called with sessions lock held.
899 */
900 int lttng_syscalls_register_event_notifier(
901 struct lttng_event_notifier_enabler *event_notifier_enabler)
902 {
903 struct lttng_event_notifier_group *group = event_notifier_enabler->group;
904 unsigned int i;
905 int ret = 0;
906
907 wrapper_vmalloc_sync_mappings();
908
909 if (!group->event_notifier_syscall_dispatch) {
910 group->event_notifier_syscall_dispatch =
911 kzalloc(sizeof(struct hlist_head) * sc_table.len,
912 GFP_KERNEL);
913 if (!group->event_notifier_syscall_dispatch)
914 return -ENOMEM;
915
916 /* Initialize all list_head */
917 for (i = 0; i < sc_table.len; i++)
918 INIT_HLIST_HEAD(&group->event_notifier_syscall_dispatch[i]);
919
920 /* Init the unknown syscall notifier list. */
921 INIT_HLIST_HEAD(&group->event_notifier_unknown_syscall_dispatch);
922 }
923
924 if (!group->event_notifier_exit_syscall_dispatch) {
925 group->event_notifier_exit_syscall_dispatch =
926 kzalloc(sizeof(struct hlist_head) * sc_table.len,
927 GFP_KERNEL);
928 if (!group->event_notifier_exit_syscall_dispatch)
929 return -ENOMEM;
930
931 /* Initialize all list_head */
932 for (i = 0; i < sc_table.len; i++)
933 INIT_HLIST_HEAD(&group->event_notifier_exit_syscall_dispatch[i]);
934
935 /* Init the unknown exit syscall notifier list. */
936 INIT_HLIST_HEAD(&group->event_notifier_exit_unknown_syscall_dispatch);
937 }
938
939 #ifdef CONFIG_COMPAT
940 if (!group->event_notifier_compat_syscall_dispatch) {
941 group->event_notifier_compat_syscall_dispatch =
942 kzalloc(sizeof(struct hlist_head) * compat_sc_table.len,
943 GFP_KERNEL);
944 if (!group->event_notifier_syscall_dispatch)
945 return -ENOMEM;
946
947 /* Initialize all list_head */
948 for (i = 0; i < compat_sc_table.len; i++)
949 INIT_HLIST_HEAD(&group->event_notifier_compat_syscall_dispatch[i]);
950
951 /* Init the unknown syscall notifier list. */
952 INIT_HLIST_HEAD(&group->event_notifier_compat_unknown_syscall_dispatch);
953 }
954
955 if (!group->event_notifier_exit_compat_syscall_dispatch) {
956 group->event_notifier_exit_compat_syscall_dispatch =
957 kzalloc(sizeof(struct hlist_head) * compat_sc_exit_table.len,
958 GFP_KERNEL);
959 if (!group->event_notifier_exit_syscall_dispatch)
960 return -ENOMEM;
961
962 /* Initialize all list_head */
963 for (i = 0; i < compat_sc_exit_table.len; i++)
964 INIT_HLIST_HEAD(&group->event_notifier_exit_compat_syscall_dispatch[i]);
965
966 /* Init the unknown exit syscall notifier list. */
967 INIT_HLIST_HEAD(&group->event_notifier_exit_compat_unknown_syscall_dispatch);
968 }
969 #endif
970
971 if (!group->sc_filter) {
972 group->sc_filter = kzalloc(sizeof(struct lttng_syscall_filter),
973 GFP_KERNEL);
974 if (!group->sc_filter)
975 return -ENOMEM;
976 }
977
978 if (!group->sys_enter_registered) {
979 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
980 (void *) syscall_entry_event_notifier_probe, group);
981 if (ret)
982 return ret;
983 group->sys_enter_registered = 1;
984 }
985
986 if (!group->sys_exit_registered) {
987 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
988 (void *) syscall_exit_event_notifier_probe, group);
989 if (ret) {
990 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
991 (void *) syscall_entry_event_notifier_probe, group));
992 return ret;
993 }
994 group->sys_exit_registered = 1;
995 }
996
997 return ret;
998 }
999
1000 static
1001 int create_unknown_event_notifier(
1002 struct lttng_event_notifier_enabler *event_notifier_enabler,
1003 enum sc_type type)
1004 {
1005 struct lttng_kernel_event_notifier_private *event_notifier_priv;
1006 struct lttng_kernel_event_notifier *event_notifier;
1007 const struct lttng_kernel_event_desc *desc;
1008 struct lttng_event_notifier_group *group = event_notifier_enabler->group;
1009 struct lttng_kernel_abi_event_notifier event_notifier_param;
1010 uint64_t user_token = event_notifier_enabler->base.user_token;
1011 uint64_t error_counter_index = event_notifier_enabler->error_counter_index;
1012 struct lttng_enabler *base_enabler = lttng_event_notifier_enabler_as_enabler(
1013 event_notifier_enabler);
1014 struct hlist_head *unknown_dispatch_list;
1015 int ret = 0;
1016 bool found = false;
1017 enum lttng_kernel_abi_syscall_abi abi;
1018 enum lttng_kernel_abi_syscall_entryexit entryexit;
1019 struct hlist_head *head;
1020
1021 switch (type) {
1022 case SC_TYPE_ENTRY:
1023 desc = &__event_desc___syscall_entry_unknown;
1024 unknown_dispatch_list = &group->event_notifier_unknown_syscall_dispatch;
1025 entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
1026 abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
1027 break;
1028 case SC_TYPE_EXIT:
1029 desc = &__event_desc___syscall_exit_unknown;
1030 unknown_dispatch_list = &group->event_notifier_exit_unknown_syscall_dispatch;
1031 entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
1032 abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
1033 break;
1034 case SC_TYPE_COMPAT_ENTRY:
1035 desc = &__event_desc___compat_syscall_entry_unknown;
1036 unknown_dispatch_list = &group->event_notifier_compat_unknown_syscall_dispatch;
1037 entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
1038 abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
1039 break;
1040 case SC_TYPE_COMPAT_EXIT:
1041 desc = &__event_desc___compat_syscall_exit_unknown;
1042 unknown_dispatch_list = &group->event_notifier_exit_compat_unknown_syscall_dispatch;
1043 entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
1044 abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
1045 break;
1046 default:
1047 BUG_ON(1);
1048 }
1049
1050 /*
1051 * Check if already created.
1052 */
1053 head = utils_borrow_hash_table_bucket(group->event_notifiers_ht.table,
1054 LTTNG_EVENT_NOTIFIER_HT_SIZE, desc->event_name);
1055 lttng_hlist_for_each_entry(event_notifier_priv, head, hlist) {
1056 if (event_notifier_priv->parent.desc == desc &&
1057 event_notifier_priv->parent.user_token == base_enabler->user_token)
1058 found = true;
1059 }
1060 if (found)
1061 goto end;
1062
1063 memset(&event_notifier_param, 0, sizeof(event_notifier_param));
1064 strncat(event_notifier_param.event.name, desc->event_name,
1065 LTTNG_KERNEL_ABI_SYM_NAME_LEN - strlen(event_notifier_param.event.name) - 1);
1066
1067 event_notifier_param.event.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
1068
1069 event_notifier_param.event.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
1070 event_notifier_param.event.u.syscall.abi = abi;
1071 event_notifier_param.event.u.syscall.entryexit = entryexit;
1072
1073 event_notifier = _lttng_event_notifier_create(desc, user_token,
1074 error_counter_index, group, &event_notifier_param,
1075 event_notifier_param.event.instrumentation);
1076 if (IS_ERR(event_notifier)) {
1077 printk(KERN_INFO "Unable to create unknown notifier %s\n",
1078 desc->event_name);
1079 ret = -ENOMEM;
1080 goto end;
1081 }
1082
1083 hlist_add_head_rcu(&event_notifier->priv->parent.u.syscall.node, unknown_dispatch_list);
1084
1085 end:
1086 return ret;
1087 }
1088
1089 static int create_matching_event_notifiers(
1090 struct lttng_event_notifier_enabler *event_notifier_enabler,
1091 const struct trace_syscall_entry *table,
1092 size_t table_len, enum sc_type type)
1093 {
1094 struct lttng_event_notifier_group *group = event_notifier_enabler->group;
1095 const struct lttng_kernel_event_desc *desc;
1096 uint64_t user_token = event_notifier_enabler->base.user_token;
1097 uint64_t error_counter_index = event_notifier_enabler->error_counter_index;
1098 unsigned int i;
1099 int ret = 0;
1100
1101 /* iterate over all syscall and create event_notifier that match */
1102 for (i = 0; i < table_len; i++) {
1103 struct lttng_kernel_event_notifier_private *event_notifier_priv;
1104 struct lttng_kernel_event_notifier *event_notifier;
1105 struct lttng_kernel_abi_event_notifier event_notifier_param;
1106 struct hlist_head *head;
1107 int found = 0;
1108
1109 desc = table[i].desc;
1110 if (!desc) {
1111 /* Unknown syscall */
1112 continue;
1113 }
1114
1115 if (!lttng_desc_match_enabler(desc,
1116 lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)))
1117 continue;
1118
1119 /*
1120 * Check if already created.
1121 */
1122 head = utils_borrow_hash_table_bucket(group->event_notifiers_ht.table,
1123 LTTNG_EVENT_NOTIFIER_HT_SIZE, desc->event_name);
1124 lttng_hlist_for_each_entry(event_notifier_priv, head, hlist) {
1125 if (event_notifier_priv->parent.desc == desc
1126 && event_notifier_priv->parent.user_token == event_notifier_enabler->base.user_token)
1127 found = 1;
1128 }
1129 if (found)
1130 continue;
1131
1132 memset(&event_notifier_param, 0, sizeof(event_notifier_param));
1133 switch (type) {
1134 case SC_TYPE_ENTRY:
1135 event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
1136 event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
1137 break;
1138 case SC_TYPE_EXIT:
1139 event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
1140 event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
1141 break;
1142 case SC_TYPE_COMPAT_ENTRY:
1143 event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
1144 event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
1145 break;
1146 case SC_TYPE_COMPAT_EXIT:
1147 event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
1148 event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
1149 break;
1150 }
1151 strncat(event_notifier_param.event.name, desc->event_name,
1152 LTTNG_KERNEL_ABI_SYM_NAME_LEN - strlen(event_notifier_param.event.name) - 1);
1153 event_notifier_param.event.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
1154 event_notifier_param.event.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
1155
1156 event_notifier = _lttng_event_notifier_create(desc, user_token,
1157 error_counter_index, group, &event_notifier_param,
1158 event_notifier_param.event.instrumentation);
1159 if (IS_ERR(event_notifier)) {
1160 printk(KERN_INFO "Unable to create event_notifier %s\n",
1161 desc->event_name);
1162 ret = -ENOMEM;
1163 goto end;
1164 }
1165
1166 event_notifier->priv->parent.u.syscall.syscall_id = i;
1167 }
1168
1169 end:
1170 return ret;
1171
1172 }
1173
1174 int lttng_syscalls_create_matching_event_notifiers(
1175 struct lttng_event_notifier_enabler *event_notifier_enabler)
1176 {
1177 int ret;
1178 struct lttng_enabler *base_enabler =
1179 lttng_event_notifier_enabler_as_enabler(event_notifier_enabler);
1180 enum lttng_kernel_abi_syscall_entryexit entryexit =
1181 base_enabler->event_param.u.syscall.entryexit;
1182
1183 if (entryexit == LTTNG_KERNEL_ABI_SYSCALL_ENTRY || entryexit == LTTNG_KERNEL_ABI_SYSCALL_ENTRYEXIT) {
1184 ret = create_matching_event_notifiers(event_notifier_enabler,
1185 sc_table.table, sc_table.len, SC_TYPE_ENTRY);
1186 if (ret)
1187 goto end;
1188
1189 ret = create_matching_event_notifiers(event_notifier_enabler,
1190 compat_sc_table.table, compat_sc_table.len,
1191 SC_TYPE_COMPAT_ENTRY);
1192 if (ret)
1193 goto end;
1194
1195 ret = create_unknown_event_notifier(event_notifier_enabler,
1196 SC_TYPE_ENTRY);
1197 if (ret)
1198 goto end;
1199
1200 ret = create_unknown_event_notifier(event_notifier_enabler,
1201 SC_TYPE_COMPAT_ENTRY);
1202 if (ret)
1203 goto end;
1204 }
1205
1206 if (entryexit == LTTNG_KERNEL_ABI_SYSCALL_EXIT || entryexit == LTTNG_KERNEL_ABI_SYSCALL_ENTRYEXIT) {
1207 ret = create_matching_event_notifiers(event_notifier_enabler,
1208 sc_exit_table.table, sc_exit_table.len,
1209 SC_TYPE_EXIT);
1210 if (ret)
1211 goto end;
1212
1213 ret = create_unknown_event_notifier(event_notifier_enabler,
1214 SC_TYPE_EXIT);
1215 if (ret)
1216 goto end;
1217
1218 ret = create_matching_event_notifiers(event_notifier_enabler,
1219 compat_sc_exit_table.table, compat_sc_exit_table.len,
1220 SC_TYPE_COMPAT_EXIT);
1221 if (ret)
1222 goto end;
1223
1224 ret = create_unknown_event_notifier(event_notifier_enabler,
1225 SC_TYPE_COMPAT_EXIT);
1226 if (ret)
1227 goto end;
1228 }
1229
1230 end:
1231 return ret;
1232 }
1233
1234 /*
1235 * Unregister the syscall event_notifier probes from the callsites.
1236 */
1237 int lttng_syscalls_unregister_event_notifier_group(
1238 struct lttng_event_notifier_group *event_notifier_group)
1239 {
1240 int ret;
1241
1242 /*
1243 * Only register the event_notifier probe on the `sys_enter` callsite for now.
1244 * At the moment, we don't think it's desirable to have one fired
1245 * event_notifier for the entry and one for the exit of a syscall.
1246 */
1247 if (event_notifier_group->sys_enter_registered) {
1248 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
1249 (void *) syscall_entry_event_notifier_probe, event_notifier_group);
1250 if (ret)
1251 return ret;
1252 event_notifier_group->sys_enter_registered = 0;
1253 }
1254 if (event_notifier_group->sys_exit_registered) {
1255 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
1256 (void *) syscall_exit_event_notifier_probe, event_notifier_group);
1257 if (ret)
1258 return ret;
1259 event_notifier_group->sys_enter_registered = 0;
1260 }
1261
1262 kfree(event_notifier_group->event_notifier_syscall_dispatch);
1263 kfree(event_notifier_group->event_notifier_exit_syscall_dispatch);
1264 #ifdef CONFIG_COMPAT
1265 kfree(event_notifier_group->event_notifier_compat_syscall_dispatch);
1266 kfree(event_notifier_group->event_notifier_exit_compat_syscall_dispatch);
1267 #endif
1268 return 0;
1269 }
1270
1271 int lttng_syscalls_unregister_channel(struct lttng_kernel_channel_buffer *chan)
1272 {
1273 int ret;
1274
1275 if (!chan->priv->parent.sc_table)
1276 return 0;
1277 if (chan->priv->parent.sys_enter_registered) {
1278 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
1279 (void *) syscall_entry_event_probe, chan);
1280 if (ret)
1281 return ret;
1282 chan->priv->parent.sys_enter_registered = 0;
1283 }
1284 if (chan->priv->parent.sys_exit_registered) {
1285 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
1286 (void *) syscall_exit_event_probe, chan);
1287 if (ret)
1288 return ret;
1289 chan->priv->parent.sys_exit_registered = 0;
1290 }
1291 return 0;
1292 }
1293
1294 int lttng_syscalls_destroy_event(struct lttng_kernel_channel_buffer *chan)
1295 {
1296 kfree(chan->priv->parent.sc_table);
1297 kfree(chan->priv->parent.sc_exit_table);
1298 #ifdef CONFIG_COMPAT
1299 kfree(chan->priv->parent.compat_sc_table);
1300 kfree(chan->priv->parent.compat_sc_exit_table);
1301 #endif
1302 kfree(chan->priv->parent.sc_filter);
1303 return 0;
1304 }
1305
1306 static
1307 int get_syscall_nr(const char *syscall_name)
1308 {
1309 int syscall_nr = -1;
1310 int i;
1311
1312 for (i = 0; i < sc_table.len; i++) {
1313 const struct trace_syscall_entry *entry;
1314 const char *it_name;
1315
1316 entry = &sc_table.table[i];
1317 if (!entry->desc)
1318 continue;
1319 it_name = entry->desc->event_name;
1320 it_name += strlen(SYSCALL_ENTRY_STR);
1321 if (!strcmp(syscall_name, it_name)) {
1322 syscall_nr = i;
1323 break;
1324 }
1325 }
1326 return syscall_nr;
1327 }
1328
1329 static
1330 int get_compat_syscall_nr(const char *syscall_name)
1331 {
1332 int syscall_nr = -1;
1333 int i;
1334
1335 for (i = 0; i < compat_sc_table.len; i++) {
1336 const struct trace_syscall_entry *entry;
1337 const char *it_name;
1338
1339 entry = &compat_sc_table.table[i];
1340 if (!entry->desc)
1341 continue;
1342 it_name = entry->desc->event_name;
1343 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
1344 if (!strcmp(syscall_name, it_name)) {
1345 syscall_nr = i;
1346 break;
1347 }
1348 }
1349 return syscall_nr;
1350 }
1351
1352 static
1353 uint32_t get_sc_tables_len(void)
1354 {
1355 return sc_table.len + compat_sc_table.len;
1356 }
1357
1358 static
1359 const char *get_syscall_name(const char *desc_name,
1360 enum lttng_syscall_abi abi,
1361 enum lttng_syscall_entryexit entryexit)
1362 {
1363 size_t prefix_len = 0;
1364
1365
1366 switch (entryexit) {
1367 case LTTNG_SYSCALL_ENTRY:
1368 switch (abi) {
1369 case LTTNG_SYSCALL_ABI_NATIVE:
1370 prefix_len = strlen(SYSCALL_ENTRY_STR);
1371 break;
1372 case LTTNG_SYSCALL_ABI_COMPAT:
1373 prefix_len = strlen(COMPAT_SYSCALL_ENTRY_STR);
1374 break;
1375 }
1376 break;
1377 case LTTNG_SYSCALL_EXIT:
1378 switch (abi) {
1379 case LTTNG_SYSCALL_ABI_NATIVE:
1380 prefix_len = strlen(SYSCALL_EXIT_STR);
1381 break;
1382 case LTTNG_SYSCALL_ABI_COMPAT:
1383 prefix_len = strlen(COMPAT_SYSCALL_EXIT_STR);
1384 break;
1385 }
1386 break;
1387 }
1388 WARN_ON_ONCE(prefix_len == 0);
1389 return desc_name + prefix_len;
1390 }
1391
1392 static
1393 int lttng_syscall_filter_enable(
1394 struct lttng_syscall_filter *filter,
1395 const char *desc_name, enum lttng_syscall_abi abi,
1396 enum lttng_syscall_entryexit entryexit)
1397 {
1398 const char *syscall_name;
1399 unsigned long *bitmap;
1400 u32 *refcount_map;
1401 int syscall_nr;
1402
1403 syscall_name = get_syscall_name(desc_name, abi, entryexit);
1404
1405 switch (abi) {
1406 case LTTNG_SYSCALL_ABI_NATIVE:
1407 syscall_nr = get_syscall_nr(syscall_name);
1408 break;
1409 case LTTNG_SYSCALL_ABI_COMPAT:
1410 syscall_nr = get_compat_syscall_nr(syscall_name);
1411 break;
1412 default:
1413 return -EINVAL;
1414 }
1415 if (syscall_nr < 0)
1416 return -ENOENT;
1417
1418 switch (entryexit) {
1419 case LTTNG_SYSCALL_ENTRY:
1420 switch (abi) {
1421 case LTTNG_SYSCALL_ABI_NATIVE:
1422 bitmap = filter->sc_entry;
1423 refcount_map = filter->sc_entry_refcount_map;
1424 break;
1425 case LTTNG_SYSCALL_ABI_COMPAT:
1426 bitmap = filter->sc_compat_entry;
1427 refcount_map = filter->sc_compat_entry_refcount_map;
1428 break;
1429 default:
1430 return -EINVAL;
1431 }
1432 break;
1433 case LTTNG_SYSCALL_EXIT:
1434 switch (abi) {
1435 case LTTNG_SYSCALL_ABI_NATIVE:
1436 bitmap = filter->sc_exit;
1437 refcount_map = filter->sc_exit_refcount_map;
1438 break;
1439 case LTTNG_SYSCALL_ABI_COMPAT:
1440 bitmap = filter->sc_compat_exit;
1441 refcount_map = filter->sc_compat_exit_refcount_map;
1442 break;
1443 default:
1444 return -EINVAL;
1445 }
1446 break;
1447 default:
1448 return -EINVAL;
1449 }
1450 if (refcount_map[syscall_nr] == U32_MAX)
1451 return -EOVERFLOW;
1452 if (refcount_map[syscall_nr]++ == 0)
1453 bitmap_set(bitmap, syscall_nr, 1);
1454 return 0;
1455 }
1456
1457 int lttng_syscall_filter_enable_event_notifier(
1458 struct lttng_kernel_event_notifier *event_notifier)
1459 {
1460 struct lttng_event_notifier_group *group = event_notifier->priv->group;
1461 unsigned int syscall_id = event_notifier->priv->parent.u.syscall.syscall_id;
1462 struct hlist_head *dispatch_list;
1463 int ret = 0;
1464
1465 WARN_ON_ONCE(event_notifier->priv->parent.instrumentation != LTTNG_KERNEL_ABI_SYSCALL);
1466
1467 /* Skip unknown syscall */
1468 if (syscall_id == -1U)
1469 return 0;
1470
1471 ret = lttng_syscall_filter_enable(group->sc_filter,
1472 event_notifier->priv->parent.desc->event_name,
1473 event_notifier->priv->parent.u.syscall.abi,
1474 event_notifier->priv->parent.u.syscall.entryexit);
1475 if (ret)
1476 return ret;
1477
1478 switch (event_notifier->priv->parent.u.syscall.entryexit) {
1479 case LTTNG_SYSCALL_ENTRY:
1480 switch (event_notifier->priv->parent.u.syscall.abi) {
1481 case LTTNG_SYSCALL_ABI_NATIVE:
1482 dispatch_list = &group->event_notifier_syscall_dispatch[syscall_id];
1483 break;
1484 case LTTNG_SYSCALL_ABI_COMPAT:
1485 dispatch_list = &group->event_notifier_compat_syscall_dispatch[syscall_id];
1486 break;
1487 default:
1488 ret = -EINVAL;
1489 goto end;
1490 }
1491 break;
1492 case LTTNG_SYSCALL_EXIT:
1493 switch (event_notifier->priv->parent.u.syscall.abi) {
1494 case LTTNG_SYSCALL_ABI_NATIVE:
1495 dispatch_list = &group->event_notifier_exit_syscall_dispatch[syscall_id];
1496 break;
1497 case LTTNG_SYSCALL_ABI_COMPAT:
1498 dispatch_list = &group->event_notifier_exit_compat_syscall_dispatch[syscall_id];
1499 break;
1500 default:
1501 ret = -EINVAL;
1502 goto end;
1503 }
1504 break;
1505 default:
1506 ret = -EINVAL;
1507 goto end;
1508 }
1509
1510 hlist_add_head_rcu(&event_notifier->priv->parent.u.syscall.node, dispatch_list);
1511
1512 end:
1513 return ret;
1514 }
1515
1516 int lttng_syscall_filter_enable_event(
1517 struct lttng_kernel_channel_buffer *channel,
1518 struct lttng_kernel_event_recorder *event_recorder)
1519 {
1520 unsigned int syscall_id = event_recorder->priv->parent.u.syscall.syscall_id;
1521
1522 WARN_ON_ONCE(event_recorder->priv->parent.instrumentation != LTTNG_KERNEL_ABI_SYSCALL);
1523
1524 /* Skip unknown syscall */
1525 if (syscall_id == -1U)
1526 return 0;
1527
1528 return lttng_syscall_filter_enable(channel->priv->parent.sc_filter,
1529 event_recorder->priv->parent.desc->event_name,
1530 event_recorder->priv->parent.u.syscall.abi,
1531 event_recorder->priv->parent.u.syscall.entryexit);
1532 }
1533
1534 static
1535 int lttng_syscall_filter_disable(
1536 struct lttng_syscall_filter *filter,
1537 const char *desc_name, enum lttng_syscall_abi abi,
1538 enum lttng_syscall_entryexit entryexit)
1539 {
1540 const char *syscall_name;
1541 unsigned long *bitmap;
1542 u32 *refcount_map;
1543 int syscall_nr;
1544
1545 syscall_name = get_syscall_name(desc_name, abi, entryexit);
1546
1547 switch (abi) {
1548 case LTTNG_SYSCALL_ABI_NATIVE:
1549 syscall_nr = get_syscall_nr(syscall_name);
1550 break;
1551 case LTTNG_SYSCALL_ABI_COMPAT:
1552 syscall_nr = get_compat_syscall_nr(syscall_name);
1553 break;
1554 default:
1555 return -EINVAL;
1556 }
1557 if (syscall_nr < 0)
1558 return -ENOENT;
1559
1560 switch (entryexit) {
1561 case LTTNG_SYSCALL_ENTRY:
1562 switch (abi) {
1563 case LTTNG_SYSCALL_ABI_NATIVE:
1564 bitmap = filter->sc_entry;
1565 refcount_map = filter->sc_entry_refcount_map;
1566 break;
1567 case LTTNG_SYSCALL_ABI_COMPAT:
1568 bitmap = filter->sc_compat_entry;
1569 refcount_map = filter->sc_compat_entry_refcount_map;
1570 break;
1571 default:
1572 return -EINVAL;
1573 }
1574 break;
1575 case LTTNG_SYSCALL_EXIT:
1576 switch (abi) {
1577 case LTTNG_SYSCALL_ABI_NATIVE:
1578 bitmap = filter->sc_exit;
1579 refcount_map = filter->sc_exit_refcount_map;
1580 break;
1581 case LTTNG_SYSCALL_ABI_COMPAT:
1582 bitmap = filter->sc_compat_exit;
1583 refcount_map = filter->sc_compat_exit_refcount_map;
1584 break;
1585 default:
1586 return -EINVAL;
1587 }
1588 break;
1589 default:
1590 return -EINVAL;
1591 }
1592 if (refcount_map[syscall_nr] == 0)
1593 return -ENOENT;
1594 if (--refcount_map[syscall_nr] == 0)
1595 bitmap_clear(bitmap, syscall_nr, 1);
1596 return 0;
1597 }
1598
1599 int lttng_syscall_filter_disable_event_notifier(
1600 struct lttng_kernel_event_notifier *event_notifier)
1601 {
1602 struct lttng_event_notifier_group *group = event_notifier->priv->group;
1603 unsigned int syscall_id = event_notifier->priv->parent.u.syscall.syscall_id;
1604 int ret;
1605
1606 WARN_ON_ONCE(event_notifier->priv->parent.instrumentation != LTTNG_KERNEL_ABI_SYSCALL);
1607
1608 /* Skip unknown syscall */
1609 if (syscall_id == -1U)
1610 return 0;
1611
1612 ret = lttng_syscall_filter_disable(group->sc_filter,
1613 event_notifier->priv->parent.desc->event_name,
1614 event_notifier->priv->parent.u.syscall.abi,
1615 event_notifier->priv->parent.u.syscall.entryexit);
1616 if (ret)
1617 return ret;
1618
1619 hlist_del_rcu(&event_notifier->priv->parent.u.syscall.node);
1620 return 0;
1621 }
1622
1623 int lttng_syscall_filter_disable_event(
1624 struct lttng_kernel_channel_buffer *channel,
1625 struct lttng_kernel_event_recorder *event_recorder)
1626 {
1627 unsigned int syscall_id = event_recorder->priv->parent.u.syscall.syscall_id;
1628
1629 /* Skip unknown syscall */
1630 if (syscall_id == -1U)
1631 return 0;
1632
1633 return lttng_syscall_filter_disable(channel->priv->parent.sc_filter,
1634 event_recorder->priv->parent.desc->event_name,
1635 event_recorder->priv->parent.u.syscall.abi,
1636 event_recorder->priv->parent.u.syscall.entryexit);
1637 }
1638
1639 static
1640 const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
1641 {
1642 const struct trace_syscall_entry *entry;
1643 int iter = 0;
1644
1645 for (entry = sc_table.table;
1646 entry < sc_table.table + sc_table.len;
1647 entry++) {
1648 if (iter++ >= *pos)
1649 return entry;
1650 }
1651 for (entry = compat_sc_table.table;
1652 entry < compat_sc_table.table + compat_sc_table.len;
1653 entry++) {
1654 if (iter++ >= *pos)
1655 return entry;
1656 }
1657 /* End of list */
1658 return NULL;
1659 }
1660
1661 static
1662 void *syscall_list_start(struct seq_file *m, loff_t *pos)
1663 {
1664 return (void *) syscall_list_get_entry(pos);
1665 }
1666
1667 static
1668 void *syscall_list_next(struct seq_file *m, void *p, loff_t *ppos)
1669 {
1670 (*ppos)++;
1671 return (void *) syscall_list_get_entry(ppos);
1672 }
1673
1674 static
1675 void syscall_list_stop(struct seq_file *m, void *p)
1676 {
1677 }
1678
1679 static
1680 int get_sc_table(const struct trace_syscall_entry *entry,
1681 const struct trace_syscall_entry **table,
1682 unsigned int *bitness)
1683 {
1684 if (entry >= sc_table.table && entry < sc_table.table + sc_table.len) {
1685 if (bitness)
1686 *bitness = BITS_PER_LONG;
1687 if (table)
1688 *table = sc_table.table;
1689 return 0;
1690 }
1691 if (!(entry >= compat_sc_table.table
1692 && entry < compat_sc_table.table + compat_sc_table.len)) {
1693 return -EINVAL;
1694 }
1695 if (bitness)
1696 *bitness = 32;
1697 if (table)
1698 *table = compat_sc_table.table;
1699 return 0;
1700 }
1701
1702 static
1703 int syscall_list_show(struct seq_file *m, void *p)
1704 {
1705 const struct trace_syscall_entry *table, *entry = p;
1706 unsigned int bitness;
1707 unsigned long index;
1708 int ret;
1709 const char *name;
1710
1711 ret = get_sc_table(entry, &table, &bitness);
1712 if (ret)
1713 return ret;
1714 if (!entry->desc)
1715 return 0;
1716 if (table == sc_table.table) {
1717 index = entry - table;
1718 name = &entry->desc->event_name[strlen(SYSCALL_ENTRY_STR)];
1719 } else {
1720 index = (entry - table) + sc_table.len;
1721 name = &entry->desc->event_name[strlen(COMPAT_SYSCALL_ENTRY_STR)];
1722 }
1723 seq_printf(m, "syscall { index = %lu; name = %s; bitness = %u; };\n",
1724 index, name, bitness);
1725 return 0;
1726 }
1727
1728 static
1729 const struct seq_operations lttng_syscall_list_seq_ops = {
1730 .start = syscall_list_start,
1731 .next = syscall_list_next,
1732 .stop = syscall_list_stop,
1733 .show = syscall_list_show,
1734 };
1735
1736 static
1737 int lttng_syscall_list_open(struct inode *inode, struct file *file)
1738 {
1739 return seq_open(file, &lttng_syscall_list_seq_ops);
1740 }
1741
1742 const struct file_operations lttng_syscall_list_fops = {
1743 .owner = THIS_MODULE,
1744 .open = lttng_syscall_list_open,
1745 .read = seq_read,
1746 .llseek = seq_lseek,
1747 .release = seq_release,
1748 };
1749
1750 /*
1751 * A syscall is enabled if it is traced for either entry or exit.
1752 */
1753 long lttng_channel_syscall_mask(struct lttng_kernel_channel_buffer *channel,
1754 struct lttng_kernel_abi_syscall_mask __user *usyscall_mask)
1755 {
1756 uint32_t len, sc_tables_len, bitmask_len;
1757 int ret = 0, bit;
1758 char *tmp_mask;
1759 struct lttng_syscall_filter *filter;
1760
1761 ret = get_user(len, &usyscall_mask->len);
1762 if (ret)
1763 return ret;
1764 sc_tables_len = get_sc_tables_len();
1765 bitmask_len = ALIGN(sc_tables_len, 8) >> 3;
1766 if (len < sc_tables_len) {
1767 return put_user(sc_tables_len, &usyscall_mask->len);
1768 }
1769 /* Array is large enough, we can copy array to user-space. */
1770 tmp_mask = kzalloc(bitmask_len, GFP_KERNEL);
1771 if (!tmp_mask)
1772 return -ENOMEM;
1773 filter = channel->priv->parent.sc_filter;
1774
1775 for (bit = 0; bit < sc_table.len; bit++) {
1776 char state;
1777
1778 if (channel->priv->parent.sc_table) {
1779 if (!(READ_ONCE(channel->priv->parent.syscall_all_entry)
1780 || READ_ONCE(channel->priv->parent.syscall_all_exit)) && filter)
1781 state = test_bit(bit, filter->sc_entry)
1782 || test_bit(bit, filter->sc_exit);
1783 else
1784 state = 1;
1785 } else {
1786 state = 0;
1787 }
1788 bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
1789 }
1790 for (; bit < sc_tables_len; bit++) {
1791 char state;
1792
1793 if (channel->priv->parent.compat_sc_table) {
1794 if (!(READ_ONCE(channel->priv->parent.syscall_all_entry)
1795 || READ_ONCE(channel->priv->parent.syscall_all_exit)) && filter)
1796 state = test_bit(bit - sc_table.len,
1797 filter->sc_compat_entry)
1798 || test_bit(bit - sc_table.len,
1799 filter->sc_compat_exit);
1800 else
1801 state = 1;
1802 } else {
1803 state = 0;
1804 }
1805 bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
1806 }
1807 if (copy_to_user(usyscall_mask->mask, tmp_mask, bitmask_len))
1808 ret = -EFAULT;
1809 kfree(tmp_mask);
1810 return ret;
1811 }
1812
1813 int lttng_abi_syscall_list(void)
1814 {
1815 struct file *syscall_list_file;
1816 int file_fd, ret;
1817
1818 file_fd = lttng_get_unused_fd();
1819 if (file_fd < 0) {
1820 ret = file_fd;
1821 goto fd_error;
1822 }
1823
1824 syscall_list_file = anon_inode_getfile("[lttng_syscall_list]",
1825 &lttng_syscall_list_fops,
1826 NULL, O_RDWR);
1827 if (IS_ERR(syscall_list_file)) {
1828 ret = PTR_ERR(syscall_list_file);
1829 goto file_error;
1830 }
1831 ret = lttng_syscall_list_fops.open(NULL, syscall_list_file);
1832 if (ret < 0)
1833 goto open_error;
1834 fd_install(file_fd, syscall_list_file);
1835 return file_fd;
1836
1837 open_error:
1838 fput(syscall_list_file);
1839 file_error:
1840 put_unused_fd(file_fd);
1841 fd_error:
1842 return ret;
1843 }
This page took 0.065907 seconds and 4 git commands to generate.