+ event->priv->u.syscall.syscall_id = syscall_nr;
+ if (dispatch_table)
+ hlist_add_head_rcu(&event->priv->u.syscall.node, dispatch_table);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static
+void lttng_syscall_event_enabler_create_matching_syscall_table_events(struct lttng_event_enabler_common *syscall_event_enabler_common,
+ const struct trace_syscall_entry *table, size_t table_len, enum sc_type type)
+{
+ struct lttng_event_ht *events_ht = lttng_get_event_ht_from_enabler(syscall_event_enabler_common);
+ const struct lttng_kernel_event_desc *desc;
+ unsigned int i;
+
+#ifndef CONFIG_COMPAT
+ if (type == SC_TYPE_COMPAT_ENTRY || type == SC_TYPE_COMPAT_EXIT)
+ return;
+#endif
+ /* iterate over all syscall and create event that match */
+ for (i = 0; i < table_len; i++) {
+ struct lttng_kernel_event_common_private *event_priv;
+ struct hlist_head *head;
+ bool found = false;
+
+ desc = table[i].desc;
+ if (!desc) {
+ /* Unknown syscall */
+ continue;
+ }
+
+ if (!lttng_desc_match_enabler(desc, syscall_event_enabler_common))
+ continue;
+
+ /*
+ * Check if already created.
+ */
+ head = utils_borrow_hash_table_bucket(events_ht->table, LTTNG_EVENT_HT_SIZE, desc->event_name);
+ lttng_hlist_for_each_entry(event_priv, head, hlist_node) {
+ if (lttng_event_enabler_desc_match_event(syscall_event_enabler_common, desc, event_priv->pub)) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ lttng_syscall_event_enabler_create_event(syscall_event_enabler_common, desc, NULL, type, i);
+ }
+}
+
+static
+bool lttng_syscall_event_enabler_is_wildcard_all(struct lttng_event_enabler_common *event_enabler)
+{
+ if (event_enabler->event_param.instrumentation != LTTNG_KERNEL_ABI_SYSCALL)
+ return false;
+ if (event_enabler->event_param.u.syscall.abi != LTTNG_KERNEL_ABI_SYSCALL_ABI_ALL)
+ return false;
+ if (event_enabler->event_param.u.syscall.match != LTTNG_KERNEL_ABI_SYSCALL_MATCH_NAME)
+ return false;
+ if (strcmp(event_enabler->event_param.name, "*"))
+ return false;
+ return true;
+}
+
+static
+void create_unknown_syscall_event(struct lttng_event_enabler_common *event_enabler, enum sc_type type)
+{
+ struct lttng_kernel_syscall_table *syscall_table = get_syscall_table_from_enabler(event_enabler);
+ struct lttng_event_ht *events_ht = lttng_get_event_ht_from_enabler(event_enabler);
+ struct lttng_kernel_event_common_private *event_priv;
+ const struct lttng_kernel_event_desc *desc;
+ struct hlist_head *unknown_dispatch_list;
+ bool found = false;
+ struct hlist_head *head;
+
+#ifndef CONFIG_COMPAT
+ if (type == SC_TYPE_COMPAT_ENTRY || type == SC_TYPE_COMPAT_EXIT)
+ return;
+#endif
+ /*
+ * Considering that currently system calls can only be enabled on a per
+ * name basis (or wildcard based on a name), unknown syscall events are
+ * only used when matching *all* system calls, because this is the only
+ * case which can be associated with an unknown system call.
+ *
+ * When enabling system call on a per system call number basis will be
+ * supported, this will need to be revisited.
+ */
+ if (!lttng_syscall_event_enabler_is_wildcard_all(event_enabler))
+ return;
+
+ switch (type) {
+ case SC_TYPE_ENTRY:
+ desc = &__event_desc___syscall_entry_unknown;
+ unknown_dispatch_list = &syscall_table->unknown_syscall_dispatch;
+ break;
+ case SC_TYPE_EXIT:
+ desc = &__event_desc___syscall_exit_unknown;
+ unknown_dispatch_list = &syscall_table->unknown_syscall_exit_dispatch;
+ break;
+ case SC_TYPE_COMPAT_ENTRY:
+ desc = &__event_desc___compat_syscall_entry_unknown;
+ unknown_dispatch_list = &syscall_table->compat_unknown_syscall_dispatch;
+ break;
+ case SC_TYPE_COMPAT_EXIT:
+ desc = &__event_desc___compat_syscall_exit_unknown;
+ unknown_dispatch_list = &syscall_table->compat_unknown_syscall_exit_dispatch;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ /*
+ * Check if already created.
+ */
+ head = utils_borrow_hash_table_bucket(events_ht->table, LTTNG_EVENT_HT_SIZE, desc->event_name);
+ lttng_hlist_for_each_entry(event_priv, head, hlist_node) {
+ if (lttng_event_enabler_desc_match_event(event_enabler, desc, event_priv->pub)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ lttng_syscall_event_enabler_create_event(event_enabler, desc, unknown_dispatch_list, type, -1U);
+}
+
+static
+void lttng_syscall_event_enabler_create_matching_events(struct lttng_event_enabler_common *event_enabler)
+{
+ enum lttng_kernel_abi_syscall_entryexit entryexit = event_enabler->event_param.u.syscall.entryexit;
+
+ if (entryexit == LTTNG_KERNEL_ABI_SYSCALL_ENTRY || entryexit == LTTNG_KERNEL_ABI_SYSCALL_ENTRYEXIT) {
+ lttng_syscall_event_enabler_create_matching_syscall_table_events(event_enabler,
+ sc_table.table, sc_table.len, SC_TYPE_ENTRY);
+ lttng_syscall_event_enabler_create_matching_syscall_table_events(event_enabler,
+ compat_sc_table.table, compat_sc_table.len, SC_TYPE_COMPAT_ENTRY);
+ create_unknown_syscall_event(event_enabler, SC_TYPE_ENTRY);
+ create_unknown_syscall_event(event_enabler, SC_TYPE_COMPAT_ENTRY);
+ }
+
+ if (entryexit == LTTNG_KERNEL_ABI_SYSCALL_EXIT || entryexit == LTTNG_KERNEL_ABI_SYSCALL_ENTRYEXIT) {
+ lttng_syscall_event_enabler_create_matching_syscall_table_events(event_enabler,
+ sc_exit_table.table, sc_exit_table.len, SC_TYPE_EXIT);
+ lttng_syscall_event_enabler_create_matching_syscall_table_events(event_enabler,
+ compat_sc_exit_table.table, compat_sc_exit_table.len, SC_TYPE_COMPAT_EXIT);
+ create_unknown_syscall_event(event_enabler, SC_TYPE_EXIT);
+ create_unknown_syscall_event(event_enabler, SC_TYPE_COMPAT_EXIT);