+static void syscall_exit_unknown(struct lttng_event *event,
+ struct pt_regs *regs, unsigned int id, long ret)
+{
+ unsigned long args[UNKNOWN_SYSCALL_NRARGS];
+
+ syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
+ if (unlikely(is_compat_task()))
+ __event_probe__compat_syscall_exit_unknown(event, id, ret,
+ args);
+ else
+ __event_probe__syscall_exit_unknown(event, id, ret, args);
+}
+
+void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
+{
+ struct lttng_channel *chan = __data;
+ struct lttng_event *event, *unknown_event;
+ const struct trace_syscall_entry *table, *entry;
+ size_t table_len;
+ long id;
+
+ id = syscall_get_nr(current, regs);
+ if (unlikely(is_compat_task())) {
+ struct lttng_syscall_filter *filter;
+
+ filter = rcu_dereference(chan->sc_filter);
+ if (filter) {
+ if (id >= NR_compat_syscalls
+ || !test_bit(id, filter->sc_compat)) {
+ /* System call filtered out. */
+ return;
+ }
+ }
+ table = compat_sc_exit_table;
+ table_len = ARRAY_SIZE(compat_sc_exit_table);
+ unknown_event = chan->compat_sc_exit_unknown;
+ } else {
+ struct lttng_syscall_filter *filter;
+
+ filter = rcu_dereference(chan->sc_filter);
+ if (filter) {
+ if (id >= NR_syscalls
+ || !test_bit(id, filter->sc)) {
+ /* System call filtered out. */
+ return;
+ }
+ }
+ table = sc_exit_table;
+ table_len = ARRAY_SIZE(sc_exit_table);
+ unknown_event = chan->sc_exit_unknown;
+ }
+ if (unlikely(id >= table_len)) {
+ syscall_exit_unknown(unknown_event, regs, id, ret);
+ return;
+ }
+ if (unlikely(is_compat_task()))
+ event = chan->compat_sc_exit_table[id];
+ else
+ event = chan->sc_exit_table[id];
+ if (unlikely(!event)) {
+ syscall_exit_unknown(unknown_event, regs, id, ret);
+ return;
+ }
+ entry = &table[id];
+ WARN_ON_ONCE(!entry);
+
+ switch (entry->nrargs) {
+ case 0:
+ {
+ void (*fptr)(void *__data, long ret) = entry->func;
+
+ fptr(event, ret);
+ break;
+ }
+ case 1:
+ {
+ void (*fptr)(void *__data,
+ long ret,
+ unsigned long arg0) = entry->func;
+ unsigned long args[1];
+
+ syscall_get_arguments(current, regs, 0, entry->nrargs, args);
+ fptr(event, ret, args[0]);
+ break;
+ }
+ case 2:
+ {
+ void (*fptr)(void *__data,
+ long ret,
+ unsigned long arg0,
+ unsigned long arg1) = entry->func;
+ unsigned long args[2];
+
+ syscall_get_arguments(current, regs, 0, entry->nrargs, args);
+ fptr(event, ret, args[0], args[1]);
+ break;
+ }
+ case 3:
+ {
+ void (*fptr)(void *__data,
+ long ret,
+ unsigned long arg0,
+ unsigned long arg1,
+ unsigned long arg2) = entry->func;
+ unsigned long args[3];
+
+ syscall_get_arguments(current, regs, 0, entry->nrargs, args);
+ fptr(event, ret, args[0], args[1], args[2]);
+ break;
+ }
+ case 4:
+ {
+ void (*fptr)(void *__data,
+ long ret,
+ unsigned long arg0,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3) = entry->func;
+ unsigned long args[4];
+
+ syscall_get_arguments(current, regs, 0, entry->nrargs, args);
+ fptr(event, ret, args[0], args[1], args[2], args[3]);
+ break;
+ }
+ case 5:
+ {
+ void (*fptr)(void *__data,
+ long ret,
+ unsigned long arg0,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4) = entry->func;
+ unsigned long args[5];
+
+ syscall_get_arguments(current, regs, 0, entry->nrargs, args);
+ fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
+ break;
+ }
+ case 6:
+ {
+ void (*fptr)(void *__data,
+ long ret,
+ unsigned long arg0,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5) = entry->func;
+ unsigned long args[6];
+
+ syscall_get_arguments(current, regs, 0, entry->nrargs, args);
+ fptr(event, ret, args[0], args[1], args[2],
+ args[3], args[4], args[5]);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/* noinline to diminish caller stack size */