Refactoring: type description structures
[lttng-modules.git] / src / lttng-syscalls.c
index 9a72245cc705a7f79f1f1c709a3ed71808cdd9f9..de84a18be2f41c1e6731e5868ab1c8fe5260933a 100644 (file)
@@ -29,6 +29,7 @@
 #include <wrapper/rcu.h>
 #include <wrapper/syscall.h>
 #include <lttng/events.h>
 #include <wrapper/rcu.h>
 #include <wrapper/syscall.h>
 #include <lttng/events.h>
+#include <lttng/utils.h>
 
 #ifndef CONFIG_COMPAT
 # ifndef is_compat_task
 
 #ifndef CONFIG_COMPAT
 # ifndef is_compat_task
@@ -59,9 +60,16 @@ enum sc_type {
 #define COMPAT_SYSCALL_EXIT_STR                __stringify(COMPAT_SYSCALL_EXIT_TOK)
 
 static
 #define COMPAT_SYSCALL_EXIT_STR                __stringify(COMPAT_SYSCALL_EXIT_TOK)
 
 static
-void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
+void syscall_entry_event_probe(void *__data, struct pt_regs *regs, long id);
 static
 static
-void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
+void syscall_exit_event_probe(void *__data, struct pt_regs *regs, long ret);
+
+static
+void syscall_entry_event_notifier_probe(void *__data, struct pt_regs *regs,
+               long id);
+static
+void syscall_exit_event_notifier_probe(void *__data, struct pt_regs *regs,
+               long ret);
 
 /*
  * Forward declarations for old kernels.
 
 /*
  * Forward declarations for old kernels.
@@ -83,7 +91,7 @@ struct timeval;
 struct itimerval;
 struct itimerspec;
 
 struct itimerval;
 struct itimerspec;
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0))
+#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,6,0))
 typedef __kernel_old_time_t time_t;
 #endif
 
 typedef __kernel_old_time_t time_t;
 #endif
 
@@ -122,7 +130,7 @@ typedef __kernel_old_time_t time_t;
 
 /* Hijack probe callback for system call enter */
 #undef TP_PROBE_CB
 
 /* Hijack probe callback for system call enter */
 #undef TP_PROBE_CB
-#define TP_PROBE_CB(_template)         &syscall_entry_probe
+#define TP_PROBE_CB(_template)         &syscall_entry_event_probe
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
                PARAMS(_fields))
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
                PARAMS(_fields))
@@ -158,7 +166,7 @@ typedef __kernel_old_time_t time_t;
 #undef _TRACE_SYSCALLS_POINTERS_H
 
 /* Hijack probe callback for compat system call enter */
 #undef _TRACE_SYSCALLS_POINTERS_H
 
 /* Hijack probe callback for compat system call enter */
-#define TP_PROBE_CB(_template)         &syscall_entry_probe
+#define TP_PROBE_CB(_template)         &syscall_entry_event_probe
 #define LTTNG_SC_COMPAT
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
 #define LTTNG_SC_COMPAT
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
@@ -207,7 +215,7 @@ typedef __kernel_old_time_t time_t;
 #define sc_inout(...)          __VA_ARGS__
 
 /* Hijack probe callback for system call exit */
 #define sc_inout(...)          __VA_ARGS__
 
 /* Hijack probe callback for system call exit */
-#define TP_PROBE_CB(_template)         &syscall_exit_probe
+#define TP_PROBE_CB(_template)         &syscall_exit_event_probe
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
                PARAMS(_fields))
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
                PARAMS(_fields))
@@ -242,7 +250,7 @@ typedef __kernel_old_time_t time_t;
 
 
 /* Hijack probe callback for compat system call exit */
 
 
 /* Hijack probe callback for compat system call exit */
-#define TP_PROBE_CB(_template)         &syscall_exit_probe
+#define TP_PROBE_CB(_template)         &syscall_exit_event_probe
 #define LTTNG_SC_COMPAT
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
 #define LTTNG_SC_COMPAT
 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
        LTTNG_TRACEPOINT_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
@@ -284,9 +292,10 @@ typedef __kernel_old_time_t time_t;
 #undef CREATE_TRACE_POINTS
 
 struct trace_syscall_entry {
 #undef CREATE_TRACE_POINTS
 
 struct trace_syscall_entry {
-       void *func;
-       const struct lttng_event_desc *desc;
-       const struct lttng_event_field *fields;
+       void *event_func;
+       void *event_notifier_func;
+       const struct lttng_kernel_event_desc *desc;
+       const struct lttng_kernel_event_field **fields;
        unsigned int nrargs;
 };
 
        unsigned int nrargs;
 };
 
@@ -300,13 +309,14 @@ struct trace_syscall_entry {
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
-               .func = __event_probe__syscall_entry_##_template, \
+               .event_func = __event_probe__syscall_entry_##_template, \
+               .event_notifier_func = __event_notifier_probe__syscall_entry_##_template, \
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___syscall_entry_##_template, \
                .desc = &__event_desc___syscall_entry_##_name,  \
        },
 
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___syscall_entry_##_template, \
                .desc = &__event_desc___syscall_entry_##_name,  \
        },
 
-/* Syscall enter tracing table */
+/* Event syscall enter tracing table */
 static const struct trace_syscall_entry sc_table[] = {
 #include <instrumentation/syscalls/headers/syscalls_integers.h>
 #include <instrumentation/syscalls/headers/syscalls_pointers.h>
 static const struct trace_syscall_entry sc_table[] = {
 #include <instrumentation/syscalls/headers/syscalls_integers.h>
 #include <instrumentation/syscalls/headers/syscalls_pointers.h>
@@ -315,13 +325,14 @@ static const struct trace_syscall_entry sc_table[] = {
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
-               .func = __event_probe__compat_syscall_entry_##_template, \
+               .event_func = __event_probe__compat_syscall_entry_##_template, \
+               .event_notifier_func = __event_notifier_probe__compat_syscall_entry_##_template, \
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___compat_syscall_entry_##_template, \
                .desc = &__event_desc___compat_syscall_entry_##_name, \
        },
 
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___compat_syscall_entry_##_template, \
                .desc = &__event_desc___compat_syscall_entry_##_name, \
        },
 
-/* Compat syscall enter table */
+/* Event compat syscall enter table */
 const struct trace_syscall_entry compat_sc_table[] = {
 #include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
 #include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
 const struct trace_syscall_entry compat_sc_table[] = {
 #include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
 #include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
@@ -337,13 +348,14 @@ const struct trace_syscall_entry compat_sc_table[] = {
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
-               .func = __event_probe__syscall_exit_##_template, \
+               .event_func = __event_probe__syscall_exit_##_template, \
+               .event_notifier_func = __event_notifier_probe__syscall_exit_##_template, \
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___syscall_exit_##_template, \
                .desc = &__event_desc___syscall_exit_##_name, \
        },
 
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___syscall_exit_##_template, \
                .desc = &__event_desc___syscall_exit_##_name, \
        },
 
-/* Syscall exit table */
+/* Event syscall exit table */
 static const struct trace_syscall_entry sc_exit_table[] = {
 #include <instrumentation/syscalls/headers/syscalls_integers.h>
 #include <instrumentation/syscalls/headers/syscalls_pointers.h>
 static const struct trace_syscall_entry sc_exit_table[] = {
 #include <instrumentation/syscalls/headers/syscalls_integers.h>
 #include <instrumentation/syscalls/headers/syscalls_pointers.h>
@@ -352,13 +364,14 @@ static const struct trace_syscall_entry sc_exit_table[] = {
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
 #undef TRACE_SYSCALL_TABLE
 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
-               .func = __event_probe__compat_syscall_exit_##_template, \
+               .event_func = __event_probe__compat_syscall_exit_##_template, \
+               .event_notifier_func = __event_notifier_probe__compat_syscall_exit_##_template, \
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___compat_syscall_exit_##_template, \
                .desc = &__event_desc___compat_syscall_exit_##_name, \
        },
 
                .nrargs = (_nrargs),                            \
                .fields = __event_fields___compat_syscall_exit_##_template, \
                .desc = &__event_desc___compat_syscall_exit_##_name, \
        },
 
-/* Compat syscall exit table */
+/* Event compat syscall exit table */
 const struct trace_syscall_entry compat_sc_exit_table[] = {
 #include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
 #include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
 const struct trace_syscall_entry compat_sc_exit_table[] = {
 #include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
 #include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
@@ -375,22 +388,259 @@ struct lttng_syscall_filter {
        DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls);
 };
 
        DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls);
 };
 
-static void syscall_entry_unknown(struct lttng_event *event,
-       struct pt_regs *regs, unsigned int id)
+static void syscall_entry_event_unknown(struct hlist_head *unknown_action_list_head,
+       struct pt_regs *regs, long id)
+{
+       unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+       struct lttng_event *event;
+
+       lttng_syscall_get_arguments(current, regs, args);
+       lttng_hlist_for_each_entry_rcu(event, unknown_action_list_head, u.syscall.node) {
+               if (unlikely(in_compat_syscall()))
+                       __event_probe__compat_syscall_entry_unknown(event, id, args);
+               else
+                       __event_probe__syscall_entry_unknown(event, id, args);
+       }
+}
+
+static void syscall_entry_event_notifier_unknown(
+               struct hlist_head *unknown_dispatch_list_head,
+               struct pt_regs *regs, long id)
 {
        unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 {
        unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+       struct lttng_event_notifier *notifier;
 
        lttng_syscall_get_arguments(current, regs, args);
 
        lttng_syscall_get_arguments(current, regs, args);
-       if (unlikely(in_compat_syscall()))
-               __event_probe__compat_syscall_entry_unknown(event, id, args);
-       else
-               __event_probe__syscall_entry_unknown(event, id, args);
+       lttng_hlist_for_each_entry_rcu(notifier, unknown_dispatch_list_head, u.syscall.node) {
+               if (unlikely(in_compat_syscall()))
+                       __event_notifier_probe__compat_syscall_entry_unknown(notifier, id, args);
+               else
+                       __event_notifier_probe__syscall_entry_unknown(notifier, id, args);
+       }
+}
+
+static void syscall_exit_event_notifier_unknown(
+               struct hlist_head *unknown_dispatch_list_head,
+               struct pt_regs *regs, long id, long ret)
+{
+       unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+       struct lttng_event_notifier *notifier;
+
+       lttng_syscall_get_arguments(current, regs, args);
+       lttng_hlist_for_each_entry_rcu(notifier, unknown_dispatch_list_head, u.syscall.node) {
+               if (unlikely(in_compat_syscall()))
+                       __event_notifier_probe__compat_syscall_exit_unknown(notifier, id, ret, args);
+               else
+                       __event_notifier_probe__syscall_exit_unknown(notifier, id, ret, args);
+       }
+}
+
+static __always_inline
+void syscall_entry_call_func(struct hlist_head *action_list,
+               void *func, unsigned int nrargs,
+               struct pt_regs *regs)
+{
+       struct lttng_event *event;
+
+       switch (nrargs) {
+       case 0:
+       {
+               void (*fptr)(void *__data) = func;
+
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event);
+               break;
+       }
+       case 1:
+       {
+               void (*fptr)(void *__data, unsigned long arg0) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, args[0]);
+               break;
+       }
+       case 2:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, args[0], args[1]);
+               break;
+       }
+       case 3:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, args[0], args[1], args[2]);
+               break;
+       }
+       case 4:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2,
+                       unsigned long arg3) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, args[0], args[1], args[2], args[3]);
+               break;
+       }
+       case 5:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2,
+                       unsigned long arg3,
+                       unsigned long arg4) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, args[0], args[1], args[2], args[3], args[4]);
+               break;
+       }
+       case 6:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2,
+                       unsigned long arg3,
+                       unsigned long arg4,
+                       unsigned long arg5) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, args[0], args[1], args[2],
+                            args[3], args[4], args[5]);
+               break;
+       }
+       default:
+               break;
+       }
 }
 
 }
 
-void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
+static __always_inline
+void syscall_entry_event_notifier_call_func(struct hlist_head *dispatch_list,
+               void *func, unsigned int nrargs, struct pt_regs *regs)
+{
+       struct lttng_event_notifier *notifier;
+
+       switch (nrargs) {
+       case 0:
+       {
+               void (*fptr)(void *__data) = func;
+
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier);
+               break;
+       }
+       case 1:
+       {
+               void (*fptr)(void *__data, unsigned long arg0) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, args[0]);
+               break;
+       }
+       case 2:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, args[0], args[1]);
+               break;
+       }
+       case 3:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, args[0], args[1], args[2]);
+               break;
+       }
+       case 4:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2,
+                       unsigned long arg3) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, args[0], args[1], args[2], args[3]);
+               break;
+       }
+       case 5:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2,
+                       unsigned long arg3,
+                       unsigned long arg4) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, args[0], args[1], args[2], args[3], args[4]);
+               break;
+       }
+       case 6:
+       {
+               void (*fptr)(void *__data,
+                       unsigned long arg0,
+                       unsigned long arg1,
+                       unsigned long arg2,
+                       unsigned long arg3,
+                       unsigned long arg4,
+                       unsigned long arg5) = func;
+               unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+
+               lttng_syscall_get_arguments(current, regs, args);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, args[0], args[1], args[2], args[3], args[4], args[5]);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+void syscall_entry_event_probe(void *__data, struct pt_regs *regs, long id)
 {
        struct lttng_channel *chan = __data;
 {
        struct lttng_channel *chan = __data;
-       struct lttng_event *event, *unknown_event;
+       struct hlist_head *action_list, *unknown_action_list;
        const struct trace_syscall_entry *table, *entry;
        size_t table_len;
 
        const struct trace_syscall_entry *table, *entry;
        size_t table_len;
 
@@ -398,121 +648,224 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_compat_syscalls
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_compat_syscalls
-                       || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_entry))) {
+                       || (!READ_ONCE(chan->syscall_all_entry) && !test_bit(id, filter->sc_compat_entry))) {
                        /* System call filtered out. */
                        return;
                }
                table = compat_sc_table;
                table_len = ARRAY_SIZE(compat_sc_table);
                        /* System call filtered out. */
                        return;
                }
                table = compat_sc_table;
                table_len = ARRAY_SIZE(compat_sc_table);
-               unknown_event = chan->sc_compat_unknown;
+               unknown_action_list = &chan->sc_compat_unknown;
        } else {
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_syscalls
        } else {
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_syscalls
-                       || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_entry))) {
+                       || (!READ_ONCE(chan->syscall_all_entry) && !test_bit(id, filter->sc_entry))) {
                        /* System call filtered out. */
                        return;
                }
                table = sc_table;
                table_len = ARRAY_SIZE(sc_table);
                        /* System call filtered out. */
                        return;
                }
                table = sc_table;
                table_len = ARRAY_SIZE(sc_table);
-               unknown_event = chan->sc_unknown;
+               unknown_action_list = &chan->sc_unknown;
        }
        if (unlikely(id < 0 || id >= table_len)) {
        }
        if (unlikely(id < 0 || id >= table_len)) {
-               syscall_entry_unknown(unknown_event, regs, id);
+               syscall_entry_event_unknown(unknown_action_list, regs, id);
                return;
        }
                return;
        }
-       if (unlikely(in_compat_syscall()))
-               event = chan->compat_sc_table[id];
-       else
-               event = chan->sc_table[id];
-       if (unlikely(!event)) {
-               syscall_entry_unknown(unknown_event, regs, id);
+
+       entry = &table[id];
+       if (!entry->event_func) {
+               syscall_entry_event_unknown(unknown_action_list, regs, id);
                return;
        }
                return;
        }
+
+       if (unlikely(in_compat_syscall())) {
+               action_list = &chan->compat_sc_table[id];
+       } else {
+               action_list = &chan->sc_table[id];
+       }
+       if (unlikely(hlist_empty(action_list)))
+               return;
+
+       syscall_entry_call_func(action_list, entry->event_func, entry->nrargs, regs);
+}
+
+void syscall_entry_event_notifier_probe(void *__data, struct pt_regs *regs,
+               long id)
+{
+       struct lttng_event_notifier_group *group = __data;
+       const struct trace_syscall_entry *table, *entry;
+       struct hlist_head *dispatch_list, *unknown_dispatch_list;
+       size_t table_len;
+
+       if (unlikely(in_compat_syscall())) {
+               struct lttng_syscall_filter *filter = group->sc_filter;
+
+               if (id < 0 || id >= NR_compat_syscalls
+                       || (!READ_ONCE(group->syscall_all_entry) &&
+                               !test_bit(id, filter->sc_compat_entry))) {
+                       /* System call filtered out. */
+                       return;
+               }
+               table = compat_sc_table;
+               table_len = ARRAY_SIZE(compat_sc_table);
+               unknown_dispatch_list = &group->event_notifier_compat_unknown_syscall_dispatch;
+       } else {
+               struct lttng_syscall_filter *filter = group->sc_filter;
+
+               if (id < 0 || id >= NR_syscalls
+                       || (!READ_ONCE(group->syscall_all_entry) &&
+                               !test_bit(id, filter->sc_entry))) {
+                       /* System call filtered out. */
+                       return;
+               }
+               table = sc_table;
+               table_len = ARRAY_SIZE(sc_table);
+               unknown_dispatch_list = &group->event_notifier_unknown_syscall_dispatch;
+       }
+       /* Check if the syscall id is out of bound. */
+       if (unlikely(id < 0 || id >= table_len)) {
+               syscall_entry_event_notifier_unknown(unknown_dispatch_list,
+                               regs, id);
+               return;
+       }
+
        entry = &table[id];
        entry = &table[id];
-       WARN_ON_ONCE(!entry);
+       if (!entry->event_notifier_func) {
+               syscall_entry_event_notifier_unknown(unknown_dispatch_list,
+                               regs, id);
+               return;
+       }
+
+       if (unlikely(in_compat_syscall())) {
+               dispatch_list = &group->event_notifier_compat_syscall_dispatch[id];
+       } else {
+               dispatch_list = &group->event_notifier_syscall_dispatch[id];
+       }
+       if (unlikely(hlist_empty(dispatch_list)))
+               return;
+
+       syscall_entry_event_notifier_call_func(dispatch_list,
+                       entry->event_notifier_func, entry->nrargs, regs);
+}
+
+static void syscall_exit_event_unknown(struct hlist_head *unknown_action_list_head,
+       struct pt_regs *regs, long id, long ret)
+{
+       unsigned long args[LTTNG_SYSCALL_NR_ARGS];
+       struct lttng_event *event;
 
 
-       switch (entry->nrargs) {
+       lttng_syscall_get_arguments(current, regs, args);
+       lttng_hlist_for_each_entry_rcu(event, unknown_action_list_head, u.syscall.node) {
+               if (unlikely(in_compat_syscall()))
+                       __event_probe__compat_syscall_exit_unknown(event, id, ret,
+                               args);
+               else
+                       __event_probe__syscall_exit_unknown(event, id, ret, args);
+       }
+}
+
+static __always_inline
+void syscall_exit_call_func(struct hlist_head *action_list,
+               void *func, unsigned int nrargs,
+               struct pt_regs *regs, long ret)
+{
+       struct lttng_event *event;
+
+       switch (nrargs) {
        case 0:
        {
        case 0:
        {
-               void (*fptr)(void *__data) = entry->func;
+               void (*fptr)(void *__data, long ret) = func;
 
 
-               fptr(event);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, ret);
                break;
        }
        case 1:
        {
                break;
        }
        case 1:
        {
-               void (*fptr)(void *__data, unsigned long arg0) = entry->func;
+               void (*fptr)(void *__data,
+                       long ret,
+                       unsigned long arg0) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, args[0]);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, ret, args[0]);
                break;
        }
        case 2:
        {
                void (*fptr)(void *__data,
                break;
        }
        case 2:
        {
                void (*fptr)(void *__data,
+                       long ret,
                        unsigned long arg0,
                        unsigned long arg0,
-                       unsigned long arg1) = entry->func;
+                       unsigned long arg1) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, args[0], args[1]);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, ret, args[0], args[1]);
                break;
        }
        case 3:
        {
                void (*fptr)(void *__data,
                break;
        }
        case 3:
        {
                void (*fptr)(void *__data,
+                       long ret,
                        unsigned long arg0,
                        unsigned long arg1,
                        unsigned long arg0,
                        unsigned long arg1,
-                       unsigned long arg2) = entry->func;
+                       unsigned long arg2) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, args[0], args[1], args[2]);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, ret, args[0], args[1], args[2]);
                break;
        }
        case 4:
        {
                void (*fptr)(void *__data,
                break;
        }
        case 4:
        {
                void (*fptr)(void *__data,
+                       long ret,
                        unsigned long arg0,
                        unsigned long arg1,
                        unsigned long arg2,
                        unsigned long arg0,
                        unsigned long arg1,
                        unsigned long arg2,
-                       unsigned long arg3) = entry->func;
+                       unsigned long arg3) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, args[0], args[1], args[2], args[3]);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, ret, args[0], args[1], args[2], args[3]);
                break;
        }
        case 5:
        {
                void (*fptr)(void *__data,
                break;
        }
        case 5:
        {
                void (*fptr)(void *__data,
+                       long ret,
                        unsigned long arg0,
                        unsigned long arg1,
                        unsigned long arg2,
                        unsigned long arg3,
                        unsigned long arg0,
                        unsigned long arg1,
                        unsigned long arg2,
                        unsigned long arg3,
-                       unsigned long arg4) = entry->func;
+                       unsigned long arg4) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, args[0], args[1], args[2], args[3], args[4]);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
                break;
        }
        case 6:
        {
                void (*fptr)(void *__data,
                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 arg0,
                        unsigned long arg1,
                        unsigned long arg2,
                        unsigned long arg3,
                        unsigned long arg4,
-                       unsigned long arg5) = entry->func;
+                       unsigned long arg5) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, args[0], args[1], args[2],
-                       args[3], args[4], args[5]);
+               lttng_hlist_for_each_entry_rcu(event, action_list, u.syscall.node)
+                       fptr(event, ret, args[0], args[1], args[2],
+                            args[3], args[4], args[5]);
                break;
        }
        default:
                break;
        }
        default:
@@ -520,83 +873,85 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
        }
 }
 
        }
 }
 
-static void syscall_exit_unknown(struct lttng_event *event,
-       struct pt_regs *regs, int id, long ret)
-{
-       unsigned long args[LTTNG_SYSCALL_NR_ARGS];
-
-       lttng_syscall_get_arguments(current, regs, args);
-       if (unlikely(in_compat_syscall()))
-               __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)
+void syscall_exit_event_probe(void *__data, struct pt_regs *regs, long ret)
 {
        struct lttng_channel *chan = __data;
 {
        struct lttng_channel *chan = __data;
-       struct lttng_event *event, *unknown_event;
+       struct hlist_head *action_list, *unknown_action_list;
        const struct trace_syscall_entry *table, *entry;
        size_t table_len;
        long id;
 
        id = syscall_get_nr(current, regs);
        const struct trace_syscall_entry *table, *entry;
        size_t table_len;
        long id;
 
        id = syscall_get_nr(current, regs);
+
        if (unlikely(in_compat_syscall())) {
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_compat_syscalls
        if (unlikely(in_compat_syscall())) {
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_compat_syscalls
-                       || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_exit))) {
+                       || (!READ_ONCE(chan->syscall_all_exit) && !test_bit(id, filter->sc_compat_exit))) {
                        /* System call filtered out. */
                        return;
                }
                table = compat_sc_exit_table;
                table_len = ARRAY_SIZE(compat_sc_exit_table);
                        /* 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;
+               unknown_action_list = &chan->compat_sc_exit_unknown;
        } else {
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_syscalls
        } else {
                struct lttng_syscall_filter *filter = chan->sc_filter;
 
                if (id < 0 || id >= NR_syscalls
-                       || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_exit))) {
+                       || (!READ_ONCE(chan->syscall_all_exit) && !test_bit(id, filter->sc_exit))) {
                        /* System call filtered out. */
                        return;
                }
                table = sc_exit_table;
                table_len = ARRAY_SIZE(sc_exit_table);
                        /* System call filtered out. */
                        return;
                }
                table = sc_exit_table;
                table_len = ARRAY_SIZE(sc_exit_table);
-               unknown_event = chan->sc_exit_unknown;
+               unknown_action_list = &chan->sc_exit_unknown;
        }
        if (unlikely(id < 0 || id >= table_len)) {
        }
        if (unlikely(id < 0 || id >= table_len)) {
-               syscall_exit_unknown(unknown_event, regs, id, ret);
+               syscall_exit_event_unknown(unknown_action_list, regs, id, ret);
                return;
        }
                return;
        }
-       if (unlikely(in_compat_syscall()))
-               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);
+
+       entry = &table[id];
+       if (!entry->event_func) {
+               syscall_exit_event_unknown(unknown_action_list, regs, id, ret);
                return;
        }
                return;
        }
-       entry = &table[id];
-       WARN_ON_ONCE(!entry);
 
 
-       switch (entry->nrargs) {
+       if (unlikely(in_compat_syscall())) {
+               action_list = &chan->compat_sc_exit_table[id];
+       } else {
+               action_list = &chan->sc_exit_table[id];
+       }
+       if (unlikely(hlist_empty(action_list)))
+               return;
+
+       syscall_exit_call_func(action_list, entry->event_func, entry->nrargs,
+                              regs, ret);
+}
+
+static __always_inline
+void syscall_exit_event_notifier_call_func(struct hlist_head *dispatch_list,
+               void *func, unsigned int nrargs, struct pt_regs *regs, long ret)
+{
+       struct lttng_event_notifier *notifier;
+
+       switch (nrargs) {
        case 0:
        {
        case 0:
        {
-               void (*fptr)(void *__data, long ret) = entry->func;
+               void (*fptr)(void *__data, long ret) = func;
 
 
-               fptr(event, ret);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, ret);
                break;
        }
        case 1:
        {
                break;
        }
        case 1:
        {
-               void (*fptr)(void *__data,
-                       long ret,
-                       unsigned long arg0) = entry->func;
+               void (*fptr)(void *__data, long ret, unsigned long arg0) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, ret, args[0]);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, ret, args[0]);
                break;
        }
        case 2:
                break;
        }
        case 2:
@@ -604,11 +959,12 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
                void (*fptr)(void *__data,
                        long ret,
                        unsigned long arg0,
                void (*fptr)(void *__data,
                        long ret,
                        unsigned long arg0,
-                       unsigned long arg1) = entry->func;
+                       unsigned long arg1) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, ret, args[0], args[1]);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, ret, args[0], args[1]);
                break;
        }
        case 3:
                break;
        }
        case 3:
@@ -617,11 +973,12 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
                        long ret,
                        unsigned long arg0,
                        unsigned long arg1,
                        long ret,
                        unsigned long arg0,
                        unsigned long arg1,
-                       unsigned long arg2) = entry->func;
+                       unsigned long arg2) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, ret, args[0], args[1], args[2]);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, ret, args[0], args[1], args[2]);
                break;
        }
        case 4:
                break;
        }
        case 4:
@@ -631,11 +988,12 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
                        unsigned long arg0,
                        unsigned long arg1,
                        unsigned long arg2,
                        unsigned long arg0,
                        unsigned long arg1,
                        unsigned long arg2,
-                       unsigned long arg3) = entry->func;
+                       unsigned long arg3) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, ret, args[0], args[1], args[2], args[3]);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, ret, args[0], args[1], args[2], args[3]);
                break;
        }
        case 5:
                break;
        }
        case 5:
@@ -646,11 +1004,12 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
                        unsigned long arg1,
                        unsigned long arg2,
                        unsigned long arg3,
                        unsigned long arg1,
                        unsigned long arg2,
                        unsigned long arg3,
-                       unsigned long arg4) = entry->func;
+                       unsigned long arg4) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, ret, args[0], args[1], args[2], args[3], args[4]);
                break;
        }
        case 6:
                break;
        }
        case 6:
@@ -662,12 +1021,12 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
                        unsigned long arg2,
                        unsigned long arg3,
                        unsigned long arg4,
                        unsigned long arg2,
                        unsigned long arg3,
                        unsigned long arg4,
-                       unsigned long arg5) = entry->func;
+                       unsigned long arg5) = func;
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
                unsigned long args[LTTNG_SYSCALL_NR_ARGS];
 
                lttng_syscall_get_arguments(current, regs, args);
-               fptr(event, ret, args[0], args[1], args[2],
-                       args[3], args[4], args[5]);
+               lttng_hlist_for_each_entry_rcu(notifier, dispatch_list, u.syscall.node)
+                       fptr(notifier, ret, args[0], args[1], args[2], args[3], args[4], args[5]);
                break;
        }
        default:
                break;
        }
        default:
@@ -675,33 +1034,111 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
        }
 }
 
        }
 }
 
+static
+void syscall_exit_event_notifier_probe(void *__data, struct pt_regs *regs,
+               long ret)
+{
+       struct lttng_event_notifier_group *group = __data;
+       const struct trace_syscall_entry *table, *entry;
+       struct hlist_head *dispatch_list, *unknown_dispatch_list;
+       size_t table_len;
+       long id;
+
+       id = syscall_get_nr(current, regs);
+
+       if (unlikely(in_compat_syscall())) {
+               struct lttng_syscall_filter *filter = group->sc_filter;
+
+               if (id < 0 || id >= NR_compat_syscalls
+                       || (!READ_ONCE(group->syscall_all_exit) &&
+                               !test_bit(id, filter->sc_compat_exit))) {
+                       /* System call filtered out. */
+                       return;
+               }
+               table = compat_sc_exit_table;
+               table_len = ARRAY_SIZE(compat_sc_exit_table);
+               unknown_dispatch_list = &group->event_notifier_exit_compat_unknown_syscall_dispatch;
+       } else {
+               struct lttng_syscall_filter *filter = group->sc_filter;
+
+               if (id < 0 || id >= NR_syscalls
+                       || (!READ_ONCE(group->syscall_all_exit) &&
+                                       !test_bit(id, filter->sc_exit))) {
+                       /* System call filtered out. */
+                       return;
+               }
+               table = sc_exit_table;
+               table_len = ARRAY_SIZE(sc_exit_table);
+               unknown_dispatch_list = &group->event_notifier_exit_unknown_syscall_dispatch;
+       }
+       /* Check if the syscall id is out of bound. */
+       if (unlikely(id < 0 || id >= table_len)) {
+               syscall_exit_event_notifier_unknown(unknown_dispatch_list,
+                               regs, id, ret);
+               return;
+       }
+
+       entry = &table[id];
+       if (!entry->event_notifier_func) {
+               syscall_entry_event_notifier_unknown(unknown_dispatch_list,
+                               regs, id);
+               return;
+       }
+
+       if (unlikely(in_compat_syscall())) {
+               dispatch_list = &group->event_notifier_exit_compat_syscall_dispatch[id];
+       } else {
+               dispatch_list = &group->event_notifier_exit_syscall_dispatch[id];
+       }
+       if (unlikely(hlist_empty(dispatch_list)))
+               return;
+
+       syscall_exit_event_notifier_call_func(dispatch_list,
+                       entry->event_notifier_func, entry->nrargs, regs, ret);
+}
 /*
  * noinline to diminish caller stack size.
  * Should be called with sessions lock held.
  */
 static
 /*
  * noinline to diminish caller stack size.
  * Should be called with sessions lock held.
  */
 static
-int fill_table(const struct trace_syscall_entry *table, size_t table_len,
-       struct lttng_event **chan_table, struct lttng_channel *chan,
+int lttng_create_syscall_event_if_missing(const struct trace_syscall_entry *table, size_t table_len,
+       struct hlist_head *chan_table, struct lttng_event_enabler *event_enabler,
        void *filter, enum sc_type type)
 {
        void *filter, enum sc_type type)
 {
-       const struct lttng_event_desc *desc;
+       struct lttng_channel *chan = event_enabler->chan;
+       struct lttng_session *session = chan->session;
        unsigned int i;
 
        unsigned int i;
 
-       /* Allocate events for each syscall, insert into table */
+       /* Allocate events for each syscall matching enabler, insert into table */
        for (i = 0; i < table_len; i++) {
        for (i = 0; i < table_len; i++) {
+               const struct lttng_kernel_event_desc *desc = table[i].desc;
                struct lttng_kernel_event ev;
                struct lttng_kernel_event ev;
-               desc = table[i].desc;
+               struct lttng_event *event;
+               struct hlist_head *head;
+               bool found = false;
 
                if (!desc) {
                        /* Unknown syscall */
                        continue;
                }
 
                if (!desc) {
                        /* Unknown syscall */
                        continue;
                }
+               if (lttng_desc_match_enabler(desc,
+                               lttng_event_enabler_as_enabler(event_enabler)) <= 0)
+                       continue;
                /*
                /*
-                * Skip those already populated by previous failed
-                * register for this channel.
+                * Check if already created.
                 */
                 */
-               if (chan_table[i])
+               head = utils_borrow_hash_table_bucket(
+                       session->events_ht.table, LTTNG_EVENT_HT_SIZE,
+                       desc->event_name);
+               lttng_hlist_for_each_entry(event, head, hlist) {
+                       if (event->desc == desc
+                               && event->chan == event_enabler->chan)
+                               found = true;
+               }
+               if (found)
                        continue;
                        continue;
+
+               /* We need to create an event for this syscall/enabler. */
                memset(&ev, 0, sizeof(ev));
                switch (type) {
                case SC_TYPE_ENTRY:
                memset(&ev, 0, sizeof(ev));
                switch (type) {
                case SC_TYPE_ENTRY:
@@ -721,21 +1158,22 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len,
                        ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
                        break;
                }
                        ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
                        break;
                }
-               strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
+               strncpy(ev.name, desc->event_name, LTTNG_KERNEL_SYM_NAME_LEN - 1);
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
-               chan_table[i] = _lttng_event_create(chan, &ev, filter,
-                                               desc, ev.instrumentation);
-               WARN_ON_ONCE(!chan_table[i]);
-               if (IS_ERR(chan_table[i])) {
+               event = _lttng_event_create(chan, &ev, filter,
+                                           desc, ev.instrumentation);
+               WARN_ON_ONCE(!event);
+               if (IS_ERR(event)) {
                        /*
                         * If something goes wrong in event registration
                         * after the first one, we have no choice but to
                         * leave the previous events in there, until
                         * deleted by session teardown.
                         */
                        /*
                         * If something goes wrong in event registration
                         * after the first one, we have no choice but to
                         * leave the previous events in there, until
                         * deleted by session teardown.
                         */
-                       return PTR_ERR(chan_table[i]);
+                       return PTR_ERR(event);
                }
                }
+               hlist_add_head(&event->u.syscall.node, &chan_table[i]);
        }
        return 0;
 }
        }
        return 0;
 }
@@ -743,8 +1181,9 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len,
 /*
  * Should be called with sessions lock held.
  */
 /*
  * Should be called with sessions lock held.
  */
-int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
+int lttng_syscalls_register_event(struct lttng_event_enabler *event_enabler, void *filter)
 {
 {
+       struct lttng_channel *chan = event_enabler->chan;
        struct lttng_kernel_event ev;
        int ret;
 
        struct lttng_kernel_event ev;
        int ret;
 
@@ -783,98 +1222,103 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
                        return -ENOMEM;
        }
 #endif
                        return -ENOMEM;
        }
 #endif
-       if (!chan->sc_unknown) {
-               const struct lttng_event_desc *desc =
+       if (hlist_empty(&chan->sc_unknown)) {
+               const struct lttng_kernel_event_desc *desc =
                        &__event_desc___syscall_entry_unknown;
                        &__event_desc___syscall_entry_unknown;
+               struct lttng_event *event;
 
                memset(&ev, 0, sizeof(ev));
 
                memset(&ev, 0, sizeof(ev));
-               strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
+               strncpy(ev.name, desc->event_name, LTTNG_KERNEL_SYM_NAME_LEN);
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
-               chan->sc_unknown = _lttng_event_create(chan, &ev, filter,
-                                               desc,
-                                               ev.instrumentation);
-               WARN_ON_ONCE(!chan->sc_unknown);
-               if (IS_ERR(chan->sc_unknown)) {
-                       return PTR_ERR(chan->sc_unknown);
+               event = _lttng_event_create(chan, &ev, filter, desc,
+                                           ev.instrumentation);
+               WARN_ON_ONCE(!event);
+               if (IS_ERR(event)) {
+                       return PTR_ERR(event);
                }
                }
+               hlist_add_head(&event->u.syscall.node, &chan->sc_unknown);
        }
 
        }
 
-       if (!chan->sc_compat_unknown) {
-               const struct lttng_event_desc *desc =
+       if (hlist_empty(&chan->sc_compat_unknown)) {
+               const struct lttng_kernel_event_desc *desc =
                        &__event_desc___compat_syscall_entry_unknown;
                        &__event_desc___compat_syscall_entry_unknown;
+               struct lttng_event *event;
 
                memset(&ev, 0, sizeof(ev));
 
                memset(&ev, 0, sizeof(ev));
-               strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
+               strncpy(ev.name, desc->event_name, LTTNG_KERNEL_SYM_NAME_LEN);
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
-               chan->sc_compat_unknown = _lttng_event_create(chan, &ev, filter,
-                                               desc,
-                                               ev.instrumentation);
-               WARN_ON_ONCE(!chan->sc_unknown);
-               if (IS_ERR(chan->sc_compat_unknown)) {
-                       return PTR_ERR(chan->sc_compat_unknown);
+               event = _lttng_event_create(chan, &ev, filter, desc,
+                                           ev.instrumentation);
+               WARN_ON_ONCE(!event);
+               if (IS_ERR(event)) {
+                       return PTR_ERR(event);
                }
                }
+               hlist_add_head(&event->u.syscall.node, &chan->sc_compat_unknown);
        }
 
        }
 
-       if (!chan->compat_sc_exit_unknown) {
-               const struct lttng_event_desc *desc =
+       if (hlist_empty(&chan->compat_sc_exit_unknown)) {
+               const struct lttng_kernel_event_desc *desc =
                        &__event_desc___compat_syscall_exit_unknown;
                        &__event_desc___compat_syscall_exit_unknown;
+               struct lttng_event *event;
 
                memset(&ev, 0, sizeof(ev));
 
                memset(&ev, 0, sizeof(ev));
-               strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
+               strncpy(ev.name, desc->event_name, LTTNG_KERNEL_SYM_NAME_LEN);
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
-               chan->compat_sc_exit_unknown = _lttng_event_create(chan, &ev,
-                                               filter, desc,
-                                               ev.instrumentation);
-               WARN_ON_ONCE(!chan->compat_sc_exit_unknown);
-               if (IS_ERR(chan->compat_sc_exit_unknown)) {
-                       return PTR_ERR(chan->compat_sc_exit_unknown);
+               event = _lttng_event_create(chan, &ev, filter, desc,
+                                           ev.instrumentation);
+               WARN_ON_ONCE(!event);
+               if (IS_ERR(event)) {
+                       return PTR_ERR(event);
                }
                }
+               hlist_add_head(&event->u.syscall.node, &chan->compat_sc_exit_unknown);
        }
 
        }
 
-       if (!chan->sc_exit_unknown) {
-               const struct lttng_event_desc *desc =
+       if (hlist_empty(&chan->sc_exit_unknown)) {
+               const struct lttng_kernel_event_desc *desc =
                        &__event_desc___syscall_exit_unknown;
                        &__event_desc___syscall_exit_unknown;
+               struct lttng_event *event;
 
                memset(&ev, 0, sizeof(ev));
 
                memset(&ev, 0, sizeof(ev));
-               strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
+               strncpy(ev.name, desc->event_name, LTTNG_KERNEL_SYM_NAME_LEN);
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
                ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_SYSCALL;
                ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
                ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
-               chan->sc_exit_unknown = _lttng_event_create(chan, &ev, filter,
-                                               desc, ev.instrumentation);
-               WARN_ON_ONCE(!chan->sc_exit_unknown);
-               if (IS_ERR(chan->sc_exit_unknown)) {
-                       return PTR_ERR(chan->sc_exit_unknown);
+               event = _lttng_event_create(chan, &ev, filter, desc,
+                                           ev.instrumentation);
+               WARN_ON_ONCE(!event);
+               if (IS_ERR(event)) {
+                       return PTR_ERR(event);
                }
                }
+               hlist_add_head(&event->u.syscall.node, &chan->sc_exit_unknown);
        }
 
        }
 
-       ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
-                       chan->sc_table, chan, filter, SC_TYPE_ENTRY);
+       ret = lttng_create_syscall_event_if_missing(sc_table, ARRAY_SIZE(sc_table),
+                       chan->sc_table, event_enabler, filter, SC_TYPE_ENTRY);
        if (ret)
                return ret;
        if (ret)
                return ret;
-       ret = fill_table(sc_exit_table, ARRAY_SIZE(sc_exit_table),
-                       chan->sc_exit_table, chan, filter, SC_TYPE_EXIT);
+       ret = lttng_create_syscall_event_if_missing(sc_exit_table, ARRAY_SIZE(sc_exit_table),
+                       chan->sc_exit_table, event_enabler, filter, SC_TYPE_EXIT);
        if (ret)
                return ret;
 
 #ifdef CONFIG_COMPAT
        if (ret)
                return ret;
 
 #ifdef CONFIG_COMPAT
-       ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
-                       chan->compat_sc_table, chan, filter,
+       ret = lttng_create_syscall_event_if_missing(compat_sc_table, ARRAY_SIZE(compat_sc_table),
+                       chan->compat_sc_table, event_enabler, filter,
                        SC_TYPE_COMPAT_ENTRY);
        if (ret)
                return ret;
                        SC_TYPE_COMPAT_ENTRY);
        if (ret)
                return ret;
-       ret = fill_table(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
-                       chan->compat_sc_exit_table, chan, filter,
+       ret = lttng_create_syscall_event_if_missing(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
+                       chan->compat_sc_exit_table, event_enabler, filter,
                        SC_TYPE_COMPAT_EXIT);
        if (ret)
                return ret;
                        SC_TYPE_COMPAT_EXIT);
        if (ret)
                return ret;
@@ -889,7 +1333,7 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
 
        if (!chan->sys_enter_registered) {
                ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
 
        if (!chan->sys_enter_registered) {
                ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
-                               (void *) syscall_entry_probe, chan);
+                               (void *) syscall_entry_event_probe, chan);
                if (ret)
                        return ret;
                chan->sys_enter_registered = 1;
                if (ret)
                        return ret;
                chan->sys_enter_registered = 1;
@@ -900,10 +1344,10 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
         */
        if (!chan->sys_exit_registered) {
                ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
         */
        if (!chan->sys_exit_registered) {
                ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
-                               (void *) syscall_exit_probe, chan);
+                               (void *) syscall_exit_event_probe, chan);
                if (ret) {
                        WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
                if (ret) {
                        WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
-                               (void *) syscall_entry_probe, chan));
+                               (void *) syscall_entry_event_probe, chan));
                        return ret;
                }
                chan->sys_exit_registered = 1;
                        return ret;
                }
                chan->sys_exit_registered = 1;
@@ -912,9 +1356,380 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
 }
 
 /*
 }
 
 /*
- * Only called at session destruction.
+ * Should be called with sessions lock held.
+ */
+int lttng_syscalls_register_event_notifier(
+               struct lttng_event_notifier_enabler *event_notifier_enabler,
+               void *filter)
+{
+       struct lttng_event_notifier_group *group = event_notifier_enabler->group;
+       unsigned int i;
+       int ret = 0;
+
+       wrapper_vmalloc_sync_mappings();
+
+       if (!group->event_notifier_syscall_dispatch) {
+               group->event_notifier_syscall_dispatch =
+                               kzalloc(sizeof(struct hlist_head) * ARRAY_SIZE(sc_table),
+                                       GFP_KERNEL);
+               if (!group->event_notifier_syscall_dispatch)
+                       return -ENOMEM;
+
+               /* Initialize all list_head */
+               for (i = 0; i < ARRAY_SIZE(sc_table); i++)
+                       INIT_HLIST_HEAD(&group->event_notifier_syscall_dispatch[i]);
+
+               /* Init the unknown syscall notifier list. */
+               INIT_HLIST_HEAD(&group->event_notifier_unknown_syscall_dispatch);
+       }
+
+       if (!group->event_notifier_exit_syscall_dispatch) {
+               group->event_notifier_exit_syscall_dispatch =
+                               kzalloc(sizeof(struct hlist_head) * ARRAY_SIZE(sc_table),
+                                       GFP_KERNEL);
+               if (!group->event_notifier_exit_syscall_dispatch)
+                       return -ENOMEM;
+
+               /* Initialize all list_head */
+               for (i = 0; i < ARRAY_SIZE(sc_table); i++)
+                       INIT_HLIST_HEAD(&group->event_notifier_exit_syscall_dispatch[i]);
+
+               /* Init the unknown exit syscall notifier list. */
+               INIT_HLIST_HEAD(&group->event_notifier_exit_unknown_syscall_dispatch);
+       }
+
+#ifdef CONFIG_COMPAT
+       if (!group->event_notifier_compat_syscall_dispatch) {
+               group->event_notifier_compat_syscall_dispatch =
+                               kzalloc(sizeof(struct hlist_head) * ARRAY_SIZE(compat_sc_table),
+                                       GFP_KERNEL);
+               if (!group->event_notifier_syscall_dispatch)
+                       return -ENOMEM;
+
+               /* Initialize all list_head */
+               for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++)
+                       INIT_HLIST_HEAD(&group->event_notifier_compat_syscall_dispatch[i]);
+
+               /* Init the unknown syscall notifier list. */
+               INIT_HLIST_HEAD(&group->event_notifier_compat_unknown_syscall_dispatch);
+       }
+
+       if (!group->event_notifier_exit_compat_syscall_dispatch) {
+               group->event_notifier_exit_compat_syscall_dispatch =
+                               kzalloc(sizeof(struct hlist_head) * ARRAY_SIZE(compat_sc_exit_table),
+                                       GFP_KERNEL);
+               if (!group->event_notifier_exit_syscall_dispatch)
+                       return -ENOMEM;
+
+               /* Initialize all list_head */
+               for (i = 0; i < ARRAY_SIZE(compat_sc_exit_table); i++)
+                       INIT_HLIST_HEAD(&group->event_notifier_exit_compat_syscall_dispatch[i]);
+
+               /* Init the unknown exit syscall notifier list. */
+               INIT_HLIST_HEAD(&group->event_notifier_exit_compat_unknown_syscall_dispatch);
+       }
+#endif
+
+       if (!group->sc_filter) {
+               group->sc_filter = kzalloc(sizeof(struct lttng_syscall_filter),
+                               GFP_KERNEL);
+               if (!group->sc_filter)
+                       return -ENOMEM;
+       }
+
+       if (!group->sys_enter_registered) {
+               ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
+                               (void *) syscall_entry_event_notifier_probe, group);
+               if (ret)
+                       return ret;
+               group->sys_enter_registered = 1;
+       }
+
+       if (!group->sys_exit_registered) {
+               ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
+                               (void *) syscall_exit_event_notifier_probe, group);
+               if (ret) {
+                       WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
+                               (void *) syscall_entry_event_notifier_probe, group));
+                       return ret;
+               }
+               group->sys_exit_registered = 1;
+       }
+
+       return ret;
+}
+
+static
+int create_unknown_event_notifier(
+               struct lttng_event_notifier_enabler *event_notifier_enabler,
+               enum sc_type type)
+{
+       struct lttng_event_notifier *notifier;
+       const struct lttng_kernel_event_desc *desc;
+       struct lttng_event_notifier_group *group = event_notifier_enabler->group;
+       struct lttng_kernel_event_notifier event_notifier_param;
+       uint64_t user_token = event_notifier_enabler->base.user_token;
+       uint64_t error_counter_index = event_notifier_enabler->error_counter_index;
+       struct lttng_enabler *base_enabler = lttng_event_notifier_enabler_as_enabler(
+               event_notifier_enabler);
+       struct hlist_head *unknown_dispatch_list;
+       int ret = 0;
+       bool found = false;
+       enum lttng_kernel_syscall_abi abi;
+       enum lttng_kernel_syscall_entryexit entryexit;
+       struct hlist_head *head;
+
+       switch (type) {
+       case SC_TYPE_ENTRY:
+               desc = &__event_desc___syscall_entry_unknown;
+               unknown_dispatch_list = &group->event_notifier_unknown_syscall_dispatch;
+               entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
+               abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
+               break;
+       case SC_TYPE_EXIT:
+               desc = &__event_desc___syscall_exit_unknown;
+               unknown_dispatch_list = &group->event_notifier_exit_unknown_syscall_dispatch;
+               entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
+               abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
+               break;
+       case SC_TYPE_COMPAT_ENTRY:
+               desc = &__event_desc___compat_syscall_entry_unknown;
+               unknown_dispatch_list = &group->event_notifier_compat_unknown_syscall_dispatch;
+               entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
+               abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
+               break;
+       case SC_TYPE_COMPAT_EXIT:
+               desc = &__event_desc___compat_syscall_exit_unknown;
+               unknown_dispatch_list = &group->event_notifier_exit_compat_unknown_syscall_dispatch;
+               entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
+               abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
+               break;
+       default:
+               BUG_ON(1);
+       }
+
+       /*
+        * Check if already created.
+        */
+       head = utils_borrow_hash_table_bucket(group->event_notifiers_ht.table,
+               LTTNG_EVENT_NOTIFIER_HT_SIZE, desc->event_name);
+       lttng_hlist_for_each_entry(notifier, head, hlist) {
+               if (notifier->desc == desc &&
+                               notifier->user_token == base_enabler->user_token)
+                       found = true;
+       }
+       if (found)
+               goto end;
+
+       memset(&event_notifier_param, 0, sizeof(event_notifier_param));
+       strncat(event_notifier_param.event.name, desc->event_name,
+               LTTNG_KERNEL_SYM_NAME_LEN - strlen(event_notifier_param.event.name) - 1);
+
+       event_notifier_param.event.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+
+       event_notifier_param.event.instrumentation = LTTNG_KERNEL_SYSCALL;
+       event_notifier_param.event.u.syscall.abi = abi;
+       event_notifier_param.event.u.syscall.entryexit = entryexit;
+
+       notifier = _lttng_event_notifier_create(desc, user_token,
+               error_counter_index, group, &event_notifier_param, NULL,
+               event_notifier_param.event.instrumentation);
+       if (IS_ERR(notifier)) {
+               printk(KERN_INFO "Unable to create unknown notifier %s\n",
+                       desc->event_name);
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       hlist_add_head_rcu(&notifier->u.syscall.node, unknown_dispatch_list);
+
+end:
+       return ret;
+}
+
+static int create_matching_event_notifiers(
+               struct lttng_event_notifier_enabler *event_notifier_enabler,
+               void *filter, const struct trace_syscall_entry *table,
+               size_t table_len, enum sc_type type)
+{
+       struct lttng_event_notifier_group *group = event_notifier_enabler->group;
+       const struct lttng_kernel_event_desc *desc;
+       uint64_t user_token = event_notifier_enabler->base.user_token;
+       uint64_t error_counter_index = event_notifier_enabler->error_counter_index;
+       unsigned int i;
+       int ret = 0;
+
+       /* iterate over all syscall and create event_notifier that match */
+       for (i = 0; i < table_len; i++) {
+               struct lttng_event_notifier *event_notifier;
+               struct lttng_kernel_event_notifier event_notifier_param;
+               struct hlist_head *head;
+               int found = 0;
+
+               desc = table[i].desc;
+               if (!desc) {
+                       /* Unknown syscall */
+                       continue;
+               }
+
+               if (!lttng_desc_match_enabler(desc,
+                               lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)))
+                       continue;
+
+               /*
+                * Check if already created.
+                */
+               head = utils_borrow_hash_table_bucket(group->event_notifiers_ht.table,
+                       LTTNG_EVENT_NOTIFIER_HT_SIZE, desc->event_name);
+               lttng_hlist_for_each_entry(event_notifier, head, hlist) {
+                       if (event_notifier->desc == desc
+                               && event_notifier->user_token == event_notifier_enabler->base.user_token)
+                               found = 1;
+               }
+               if (found)
+                       continue;
+
+               memset(&event_notifier_param, 0, sizeof(event_notifier_param));
+               switch (type) {
+               case SC_TYPE_ENTRY:
+                       event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
+                       event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
+                       break;
+               case SC_TYPE_EXIT:
+                       event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
+                       event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
+                       break;
+               case SC_TYPE_COMPAT_ENTRY:
+                       event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
+                       event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
+                       break;
+               case SC_TYPE_COMPAT_EXIT:
+                       event_notifier_param.event.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
+                       event_notifier_param.event.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
+                       break;
+               }
+               strncat(event_notifier_param.event.name, desc->event_name,
+                       LTTNG_KERNEL_SYM_NAME_LEN - strlen(event_notifier_param.event.name) - 1);
+               event_notifier_param.event.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+               event_notifier_param.event.instrumentation = LTTNG_KERNEL_SYSCALL;
+
+               event_notifier = _lttng_event_notifier_create(desc, user_token,
+                       error_counter_index, group, &event_notifier_param,
+                       filter, event_notifier_param.event.instrumentation);
+               if (IS_ERR(event_notifier)) {
+                       printk(KERN_INFO "Unable to create event_notifier %s\n",
+                               desc->event_name);
+                       ret = -ENOMEM;
+                       goto end;
+               }
+
+               event_notifier->u.syscall.syscall_id = i;
+       }
+
+end:
+       return ret;
+
+}
+
+int lttng_syscals_create_matching_event_notifiers(
+               struct lttng_event_notifier_enabler *event_notifier_enabler,
+               void *filter)
+{
+       int ret;
+       struct lttng_enabler *base_enabler =
+                       lttng_event_notifier_enabler_as_enabler(event_notifier_enabler);
+       enum lttng_kernel_syscall_entryexit entryexit =
+                       base_enabler->event_param.u.syscall.entryexit;
+
+       if (entryexit == LTTNG_KERNEL_SYSCALL_ENTRY || entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT) {
+               ret = create_matching_event_notifiers(event_notifier_enabler,
+                       filter, sc_table, ARRAY_SIZE(sc_table), SC_TYPE_ENTRY);
+               if (ret)
+                       goto end;
+
+               ret = create_matching_event_notifiers(event_notifier_enabler,
+                       filter, compat_sc_table, ARRAY_SIZE(compat_sc_table),
+                       SC_TYPE_COMPAT_ENTRY);
+               if (ret)
+                       goto end;
+
+               ret = create_unknown_event_notifier(event_notifier_enabler,
+                               SC_TYPE_ENTRY);
+               if (ret)
+                       goto end;
+
+               ret = create_unknown_event_notifier(event_notifier_enabler,
+                               SC_TYPE_COMPAT_ENTRY);
+               if (ret)
+                       goto end;
+       }
+
+       if (entryexit == LTTNG_KERNEL_SYSCALL_EXIT || entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT) {
+               ret = create_matching_event_notifiers(event_notifier_enabler,
+                       filter, sc_exit_table, ARRAY_SIZE(sc_exit_table),
+                       SC_TYPE_EXIT);
+               if (ret)
+                       goto end;
+
+               ret = create_unknown_event_notifier(event_notifier_enabler,
+                               SC_TYPE_EXIT);
+               if (ret)
+                       goto end;
+
+               ret = create_matching_event_notifiers(event_notifier_enabler,
+                       filter, compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
+                       SC_TYPE_COMPAT_EXIT);
+               if (ret)
+                       goto end;
+
+               ret = create_unknown_event_notifier(event_notifier_enabler,
+                               SC_TYPE_COMPAT_EXIT);
+               if (ret)
+                       goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Unregister the syscall event_notifier probes from the callsites.
  */
  */
-int lttng_syscalls_unregister(struct lttng_channel *chan)
+int lttng_syscalls_unregister_event_notifier_group(
+               struct lttng_event_notifier_group *event_notifier_group)
+{
+       int ret;
+
+       /*
+        * Only register the event_notifier probe on the `sys_enter` callsite for now.
+        * At the moment, we don't think it's desirable to have one fired
+        * event_notifier for the entry and one for the exit of a syscall.
+        */
+       if (event_notifier_group->sys_enter_registered) {
+               ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
+                               (void *) syscall_entry_event_notifier_probe, event_notifier_group);
+               if (ret)
+                       return ret;
+               event_notifier_group->sys_enter_registered = 0;
+       }
+       if (event_notifier_group->sys_exit_registered) {
+               ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
+                               (void *) syscall_exit_event_notifier_probe, event_notifier_group);
+               if (ret)
+                       return ret;
+               event_notifier_group->sys_enter_registered = 0;
+       }
+
+       kfree(event_notifier_group->event_notifier_syscall_dispatch);
+       kfree(event_notifier_group->event_notifier_exit_syscall_dispatch);
+#ifdef CONFIG_COMPAT
+       kfree(event_notifier_group->event_notifier_compat_syscall_dispatch);
+       kfree(event_notifier_group->event_notifier_exit_compat_syscall_dispatch);
+#endif
+       return 0;
+}
+
+int lttng_syscalls_unregister_channel(struct lttng_channel *chan)
 {
        int ret;
 
 {
        int ret;
 
@@ -922,14 +1737,14 @@ int lttng_syscalls_unregister(struct lttng_channel *chan)
                return 0;
        if (chan->sys_enter_registered) {
                ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
                return 0;
        if (chan->sys_enter_registered) {
                ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
-                               (void *) syscall_entry_probe, chan);
+                               (void *) syscall_entry_event_probe, chan);
                if (ret)
                        return ret;
                chan->sys_enter_registered = 0;
        }
        if (chan->sys_exit_registered) {
                ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
                if (ret)
                        return ret;
                chan->sys_enter_registered = 0;
        }
        if (chan->sys_exit_registered) {
                ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
-                               (void *) syscall_exit_probe, chan);
+                               (void *) syscall_exit_event_probe, chan);
                if (ret)
                        return ret;
                chan->sys_exit_registered = 0;
                if (ret)
                        return ret;
                chan->sys_exit_registered = 0;
@@ -937,7 +1752,7 @@ int lttng_syscalls_unregister(struct lttng_channel *chan)
        return 0;
 }
 
        return 0;
 }
 
-int lttng_syscalls_destroy(struct lttng_channel *chan)
+int lttng_syscalls_destroy_event(struct lttng_channel *chan)
 {
        kfree(chan->sc_table);
        kfree(chan->sc_exit_table);
 {
        kfree(chan->sc_table);
        kfree(chan->sc_exit_table);
@@ -962,7 +1777,7 @@ int get_syscall_nr(const char *syscall_name)
                entry = &sc_table[i];
                if (!entry->desc)
                        continue;
                entry = &sc_table[i];
                if (!entry->desc)
                        continue;
-               it_name = entry->desc->name;
+               it_name = entry->desc->event_name;
                it_name += strlen(SYSCALL_ENTRY_STR);
                if (!strcmp(syscall_name, it_name)) {
                        syscall_nr = i;
                it_name += strlen(SYSCALL_ENTRY_STR);
                if (!strcmp(syscall_name, it_name)) {
                        syscall_nr = i;
@@ -985,7 +1800,7 @@ int get_compat_syscall_nr(const char *syscall_name)
                entry = &compat_sc_table[i];
                if (!entry->desc)
                        continue;
                entry = &compat_sc_table[i];
                if (!entry->desc)
                        continue;
-               it_name = entry->desc->name;
+               it_name = entry->desc->event_name;
                it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
                if (!strcmp(syscall_name, it_name)) {
                        syscall_nr = i;
                it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
                if (!strcmp(syscall_name, it_name)) {
                        syscall_nr = i;
@@ -1002,15 +1817,16 @@ uint32_t get_sc_tables_len(void)
 }
 
 static
 }
 
 static
-const char *get_syscall_name(struct lttng_event *event)
+const char *get_syscall_name(const char *desc_name,
+               enum lttng_syscall_abi abi,
+               enum lttng_syscall_entryexit entryexit)
 {
        size_t prefix_len = 0;
 
 {
        size_t prefix_len = 0;
 
-       WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_SYSCALL);
 
 
-       switch (event->u.syscall.entryexit) {
+       switch (entryexit) {
        case LTTNG_SYSCALL_ENTRY:
        case LTTNG_SYSCALL_ENTRY:
-               switch (event->u.syscall.abi) {
+               switch (abi) {
                case LTTNG_SYSCALL_ABI_NATIVE:
                        prefix_len = strlen(SYSCALL_ENTRY_STR);
                        break;
                case LTTNG_SYSCALL_ABI_NATIVE:
                        prefix_len = strlen(SYSCALL_ENTRY_STR);
                        break;
@@ -1020,7 +1836,7 @@ const char *get_syscall_name(struct lttng_event *event)
                }
                break;
        case LTTNG_SYSCALL_EXIT:
                }
                break;
        case LTTNG_SYSCALL_EXIT:
-               switch (event->u.syscall.abi) {
+               switch (abi) {
                case LTTNG_SYSCALL_ABI_NATIVE:
                        prefix_len = strlen(SYSCALL_EXIT_STR);
                        break;
                case LTTNG_SYSCALL_ABI_NATIVE:
                        prefix_len = strlen(SYSCALL_EXIT_STR);
                        break;
@@ -1031,22 +1847,22 @@ const char *get_syscall_name(struct lttng_event *event)
                break;
        }
        WARN_ON_ONCE(prefix_len == 0);
                break;
        }
        WARN_ON_ONCE(prefix_len == 0);
-       return event->desc->name + prefix_len;
+       return desc_name + prefix_len;
 }
 
 }
 
-int lttng_syscall_filter_enable(struct lttng_channel *chan,
-               struct lttng_event *event)
+static
+int lttng_syscall_filter_enable(
+               struct lttng_syscall_filter *filter,
+               const char *desc_name, enum lttng_syscall_abi abi,
+               enum lttng_syscall_entryexit entryexit)
 {
 {
-       struct lttng_syscall_filter *filter = chan->sc_filter;
        const char *syscall_name;
        unsigned long *bitmap;
        int syscall_nr;
 
        const char *syscall_name;
        unsigned long *bitmap;
        int syscall_nr;
 
-       WARN_ON_ONCE(!chan->sc_table);
+       syscall_name = get_syscall_name(desc_name, abi, entryexit);
 
 
-       syscall_name = get_syscall_name(event);
-
-       switch (event->u.syscall.abi) {
+       switch (abi) {
        case LTTNG_SYSCALL_ABI_NATIVE:
                syscall_nr = get_syscall_nr(syscall_name);
                break;
        case LTTNG_SYSCALL_ABI_NATIVE:
                syscall_nr = get_syscall_nr(syscall_name);
                break;
@@ -1059,9 +1875,9 @@ int lttng_syscall_filter_enable(struct lttng_channel *chan,
        if (syscall_nr < 0)
                return -ENOENT;
 
        if (syscall_nr < 0)
                return -ENOENT;
 
-       switch (event->u.syscall.entryexit) {
+       switch (entryexit) {
        case LTTNG_SYSCALL_ENTRY:
        case LTTNG_SYSCALL_ENTRY:
-               switch (event->u.syscall.abi) {
+               switch (abi) {
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_entry;
                        break;
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_entry;
                        break;
@@ -1073,7 +1889,7 @@ int lttng_syscall_filter_enable(struct lttng_channel *chan,
                }
                break;
        case LTTNG_SYSCALL_EXIT:
                }
                break;
        case LTTNG_SYSCALL_EXIT:
-               switch (event->u.syscall.abi) {
+               switch (abi) {
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_exit;
                        break;
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_exit;
                        break;
@@ -1093,19 +1909,85 @@ int lttng_syscall_filter_enable(struct lttng_channel *chan,
        return 0;
 }
 
        return 0;
 }
 
-int lttng_syscall_filter_disable(struct lttng_channel *chan,
+int lttng_syscall_filter_enable_event_notifier(
+               struct lttng_event_notifier *notifier)
+{
+       struct lttng_event_notifier_group *group = notifier->group;
+       unsigned int syscall_id = notifier->u.syscall.syscall_id;
+       struct hlist_head *dispatch_list;
+       int ret = 0;
+
+       WARN_ON_ONCE(notifier->instrumentation != LTTNG_KERNEL_SYSCALL);
+
+       ret = lttng_syscall_filter_enable(group->sc_filter,
+               notifier->desc->event_name, notifier->u.syscall.abi,
+               notifier->u.syscall.entryexit);
+       if (ret) {
+               goto end;
+       }
+
+       switch (notifier->u.syscall.entryexit) {
+       case LTTNG_SYSCALL_ENTRY:
+               switch (notifier->u.syscall.abi) {
+               case LTTNG_SYSCALL_ABI_NATIVE:
+                       dispatch_list = &group->event_notifier_syscall_dispatch[syscall_id];
+                       break;
+               case LTTNG_SYSCALL_ABI_COMPAT:
+                       dispatch_list = &group->event_notifier_compat_syscall_dispatch[syscall_id];
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto end;
+               }
+               break;
+       case LTTNG_SYSCALL_EXIT:
+               switch (notifier->u.syscall.abi) {
+               case LTTNG_SYSCALL_ABI_NATIVE:
+                       dispatch_list = &group->event_notifier_exit_syscall_dispatch[syscall_id];
+                       break;
+               case LTTNG_SYSCALL_ABI_COMPAT:
+                       dispatch_list = &group->event_notifier_exit_compat_syscall_dispatch[syscall_id];
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto end;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               goto end;
+       }
+
+       hlist_add_head_rcu(&notifier->u.syscall.node, dispatch_list);
+
+end:
+       return ret ;
+}
+
+int lttng_syscall_filter_enable_event(
+               struct lttng_channel *channel,
                struct lttng_event *event)
 {
                struct lttng_event *event)
 {
-       struct lttng_syscall_filter *filter = chan->sc_filter;
+       WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_SYSCALL);
+
+       return lttng_syscall_filter_enable(channel->sc_filter,
+               event->desc->event_name, event->u.syscall.abi,
+               event->u.syscall.entryexit);
+}
+
+static
+int lttng_syscall_filter_disable(
+               struct lttng_syscall_filter *filter,
+               const char *desc_name, enum lttng_syscall_abi abi,
+               enum lttng_syscall_entryexit entryexit)
+{
        const char *syscall_name;
        unsigned long *bitmap;
        int syscall_nr;
 
        const char *syscall_name;
        unsigned long *bitmap;
        int syscall_nr;
 
-       WARN_ON_ONCE(!chan->sc_table);
+       syscall_name = get_syscall_name(desc_name, abi, entryexit);
 
 
-       syscall_name = get_syscall_name(event);
-
-       switch (event->u.syscall.abi) {
+       switch (abi) {
        case LTTNG_SYSCALL_ABI_NATIVE:
                syscall_nr = get_syscall_nr(syscall_name);
                break;
        case LTTNG_SYSCALL_ABI_NATIVE:
                syscall_nr = get_syscall_nr(syscall_name);
                break;
@@ -1118,9 +2000,9 @@ int lttng_syscall_filter_disable(struct lttng_channel *chan,
        if (syscall_nr < 0)
                return -ENOENT;
 
        if (syscall_nr < 0)
                return -ENOENT;
 
-       switch (event->u.syscall.entryexit) {
+       switch (entryexit) {
        case LTTNG_SYSCALL_ENTRY:
        case LTTNG_SYSCALL_ENTRY:
-               switch (event->u.syscall.abi) {
+               switch (abi) {
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_entry;
                        break;
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_entry;
                        break;
@@ -1132,7 +2014,7 @@ int lttng_syscall_filter_disable(struct lttng_channel *chan,
                }
                break;
        case LTTNG_SYSCALL_EXIT:
                }
                break;
        case LTTNG_SYSCALL_EXIT:
-               switch (event->u.syscall.abi) {
+               switch (abi) {
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_exit;
                        break;
                case LTTNG_SYSCALL_ABI_NATIVE:
                        bitmap = filter->sc_exit;
                        break;
@@ -1153,6 +2035,32 @@ int lttng_syscall_filter_disable(struct lttng_channel *chan,
        return 0;
 }
 
        return 0;
 }
 
+int lttng_syscall_filter_disable_event_notifier(
+               struct lttng_event_notifier *notifier)
+{
+       struct lttng_event_notifier_group *group = notifier->group;
+       int ret;
+
+       WARN_ON_ONCE(notifier->instrumentation != LTTNG_KERNEL_SYSCALL);
+
+       ret = lttng_syscall_filter_disable(group->sc_filter,
+               notifier->desc->event_name, notifier->u.syscall.abi,
+               notifier->u.syscall.entryexit);
+       WARN_ON_ONCE(ret != 0);
+
+       hlist_del_rcu(&notifier->u.syscall.node);
+       return 0;
+}
+
+int lttng_syscall_filter_disable_event(
+               struct lttng_channel *channel,
+               struct lttng_event *event)
+{
+       return lttng_syscall_filter_disable(channel->sc_filter,
+               event->desc->event_name, event->u.syscall.abi,
+               event->u.syscall.entryexit);
+}
+
 static
 const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
 {
 static
 const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
 {
@@ -1232,10 +2140,10 @@ int syscall_list_show(struct seq_file *m, void *p)
                return 0;
        if (table == sc_table) {
                index = entry - table;
                return 0;
        if (table == sc_table) {
                index = entry - table;
-               name = &entry->desc->name[strlen(SYSCALL_ENTRY_STR)];
+               name = &entry->desc->event_name[strlen(SYSCALL_ENTRY_STR)];
        } else {
                index = (entry - table) + ARRAY_SIZE(sc_table);
        } else {
                index = (entry - table) + ARRAY_SIZE(sc_table);
-               name = &entry->desc->name[strlen(COMPAT_SYSCALL_ENTRY_STR)];
+               name = &entry->desc->event_name[strlen(COMPAT_SYSCALL_ENTRY_STR)];
        }
        seq_printf(m,   "syscall { index = %lu; name = %s; bitness = %u; };\n",
                index, name, bitness);
        }
        seq_printf(m,   "syscall { index = %lu; name = %s; bitness = %u; };\n",
                index, name, bitness);
@@ -1293,7 +2201,8 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel,
                char state;
 
                if (channel->sc_table) {
                char state;
 
                if (channel->sc_table) {
-                       if (!READ_ONCE(channel->syscall_all) && filter)
+                       if (!(READ_ONCE(channel->syscall_all_entry)
+                                       || READ_ONCE(channel->syscall_all_exit)) && filter)
                                state = test_bit(bit, filter->sc_entry)
                                        || test_bit(bit, filter->sc_exit);
                        else
                                state = test_bit(bit, filter->sc_entry)
                                        || test_bit(bit, filter->sc_exit);
                        else
@@ -1307,7 +2216,8 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel,
                char state;
 
                if (channel->compat_sc_table) {
                char state;
 
                if (channel->compat_sc_table) {
-                       if (!READ_ONCE(channel->syscall_all) && filter)
+                       if (!(READ_ONCE(channel->syscall_all_entry)
+                                       || READ_ONCE(channel->syscall_all_exit)) && filter)
                                state = test_bit(bit - ARRAY_SIZE(sc_table),
                                                filter->sc_compat_entry)
                                        || test_bit(bit - ARRAY_SIZE(sc_table),
                                state = test_bit(bit - ARRAY_SIZE(sc_table),
                                                filter->sc_compat_entry)
                                        || test_bit(bit - ARRAY_SIZE(sc_table),
This page took 0.04684 seconds and 4 git commands to generate.