+ if (chan->sys_enter_registered) {
+ ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
+ (void *) syscall_entry_probe, chan);
+ 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);
+ if (ret)
+ return ret;
+ chan->sys_exit_registered = 0;
+ }
+ return 0;
+}
+
+int lttng_syscalls_destroy(struct lttng_channel *chan)
+{
+ kfree(chan->sc_table);
+ kfree(chan->sc_exit_table);
+#ifdef CONFIG_COMPAT
+ kfree(chan->compat_sc_table);
+ kfree(chan->compat_sc_exit_table);
+#endif
+ kfree(chan->sc_filter);
+ return 0;
+}
+
+static
+int get_syscall_nr(const char *syscall_name)
+{
+ int syscall_nr = -1;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
+ const struct trace_syscall_entry *entry;
+ const char *it_name;
+
+ entry = &sc_table[i];
+ if (!entry->desc)
+ continue;
+ it_name = entry->desc->name;
+ it_name += strlen(SYSCALL_ENTRY_STR);
+ if (!strcmp(syscall_name, it_name)) {
+ syscall_nr = i;
+ break;
+ }
+ }
+ return syscall_nr;
+}
+
+static
+int get_compat_syscall_nr(const char *syscall_name)
+{
+ int syscall_nr = -1;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++) {
+ const struct trace_syscall_entry *entry;
+ const char *it_name;
+
+ entry = &compat_sc_table[i];
+ if (!entry->desc)
+ continue;
+ it_name = entry->desc->name;
+ it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
+ if (!strcmp(syscall_name, it_name)) {
+ syscall_nr = i;
+ break;
+ }
+ }
+ return syscall_nr;
+}
+
+static
+uint32_t get_sc_tables_len(void)
+{
+ return ARRAY_SIZE(sc_table) + ARRAY_SIZE(compat_sc_table);
+}
+
+static
+const char *get_syscall_name(struct lttng_event *event)
+{
+ size_t prefix_len = 0;
+
+ WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_SYSCALL);
+
+ switch (event->u.syscall.entryexit) {
+ case LTTNG_SYSCALL_ENTRY:
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ prefix_len = strlen(SYSCALL_ENTRY_STR);
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ prefix_len = strlen(COMPAT_SYSCALL_ENTRY_STR);
+ break;
+ }
+ break;
+ case LTTNG_SYSCALL_EXIT:
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ prefix_len = strlen(SYSCALL_EXIT_STR);
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ prefix_len = strlen(COMPAT_SYSCALL_EXIT_STR);
+ break;
+ }
+ break;
+ }
+ WARN_ON_ONCE(prefix_len == 0);
+ return event->desc->name + prefix_len;
+}
+
+int lttng_syscall_filter_enable(struct lttng_channel *chan,
+ struct lttng_event *event)
+{
+ struct lttng_syscall_filter *filter = chan->sc_filter;
+ const char *syscall_name;
+ unsigned long *bitmap;
+ int syscall_nr;
+
+ WARN_ON_ONCE(!chan->sc_table);
+
+ syscall_name = get_syscall_name(event);
+
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ syscall_nr = get_syscall_nr(syscall_name);
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ syscall_nr = get_compat_syscall_nr(syscall_name);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (syscall_nr < 0)
+ return -ENOENT;
+
+
+ switch (event->u.syscall.entryexit) {
+ case LTTNG_SYSCALL_ENTRY:
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ bitmap = filter->sc_entry;
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ bitmap = filter->sc_compat_entry;
+ break;
+ }
+ break;
+ case LTTNG_SYSCALL_EXIT:
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ bitmap = filter->sc_exit;
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ bitmap = filter->sc_compat_exit;
+ break;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (test_bit(syscall_nr, bitmap))
+ return -EEXIST;
+ bitmap_set(bitmap, syscall_nr, 1);
+ return 0;
+}
+
+int lttng_syscall_filter_disable(struct lttng_channel *chan,
+ struct lttng_event *event)
+{
+ struct lttng_syscall_filter *filter = chan->sc_filter;
+ const char *syscall_name;
+ unsigned long *bitmap;
+ int syscall_nr;
+
+ WARN_ON_ONCE(!chan->sc_table);
+
+ syscall_name = get_syscall_name(event);
+
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ syscall_nr = get_syscall_nr(syscall_name);
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ syscall_nr = get_compat_syscall_nr(syscall_name);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (syscall_nr < 0)
+ return -ENOENT;
+
+
+ switch (event->u.syscall.entryexit) {
+ case LTTNG_SYSCALL_ENTRY:
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ bitmap = filter->sc_entry;
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ bitmap = filter->sc_compat_entry;
+ break;
+ }
+ break;
+ case LTTNG_SYSCALL_EXIT:
+ switch (event->u.syscall.abi) {
+ case LTTNG_SYSCALL_ABI_NATIVE:
+ bitmap = filter->sc_exit;
+ break;
+ case LTTNG_SYSCALL_ABI_COMPAT:
+ bitmap = filter->sc_compat_exit;
+ break;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!test_bit(syscall_nr, bitmap))
+ return -EEXIST;
+ bitmap_clear(bitmap, syscall_nr, 1);
+
+ return 0;
+}
+
+static
+const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
+{
+ const struct trace_syscall_entry *entry;
+ int iter = 0;
+
+ for (entry = sc_table;
+ entry < sc_table + ARRAY_SIZE(sc_table);
+ entry++) {
+ if (iter++ >= *pos)
+ return entry;
+ }
+ for (entry = compat_sc_table;
+ entry < compat_sc_table + ARRAY_SIZE(compat_sc_table);
+ entry++) {
+ if (iter++ >= *pos)
+ return entry;
+ }
+ /* End of list */
+ return NULL;
+}
+
+static
+void *syscall_list_start(struct seq_file *m, loff_t *pos)
+{
+ return (void *) syscall_list_get_entry(pos);
+}
+
+static
+void *syscall_list_next(struct seq_file *m, void *p, loff_t *ppos)
+{
+ (*ppos)++;
+ return (void *) syscall_list_get_entry(ppos);
+}
+
+static
+void syscall_list_stop(struct seq_file *m, void *p)
+{
+}
+
+static
+int get_sc_table(const struct trace_syscall_entry *entry,
+ const struct trace_syscall_entry **table,
+ unsigned int *bitness)
+{
+ if (entry >= sc_table && entry < sc_table + ARRAY_SIZE(sc_table)) {
+ if (bitness)
+ *bitness = BITS_PER_LONG;
+ if (table)
+ *table = sc_table;
+ return 0;
+ }
+ if (!(entry >= compat_sc_table
+ && entry < compat_sc_table + ARRAY_SIZE(compat_sc_table))) {
+ return -EINVAL;
+ }
+ if (bitness)
+ *bitness = 32;
+ if (table)
+ *table = compat_sc_table;
+ return 0;
+}
+
+static
+int syscall_list_show(struct seq_file *m, void *p)
+{
+ const struct trace_syscall_entry *table, *entry = p;
+ unsigned int bitness;
+ unsigned long index;
+ int ret;
+ const char *name;
+
+ ret = get_sc_table(entry, &table, &bitness);