+
+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);
+ if (ret)
+ return ret;
+ if (!entry->desc)
+ return 0;
+ if (table == sc_table) {
+ index = entry - table;
+ name = &entry->desc->name[strlen(SYSCALL_ENTRY_STR)];
+ } else {
+ index = (entry - table) + ARRAY_SIZE(sc_table);
+ name = &entry->desc->name[strlen(COMPAT_SYSCALL_ENTRY_STR)];
+ }
+ seq_printf(m, "syscall { index = %lu; name = %s; bitness = %u; };\n",
+ index, name, bitness);
+ return 0;
+}
+
+static
+const struct seq_operations lttng_syscall_list_seq_ops = {
+ .start = syscall_list_start,
+ .next = syscall_list_next,
+ .stop = syscall_list_stop,
+ .show = syscall_list_show,
+};
+
+static
+int lttng_syscall_list_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, <tng_syscall_list_seq_ops);
+}
+
+const struct file_operations lttng_syscall_list_fops = {
+ .owner = THIS_MODULE,
+ .open = lttng_syscall_list_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+long lttng_channel_syscall_mask(struct lttng_channel *channel,
+ struct lttng_kernel_syscall_mask __user *usyscall_mask)
+{
+ uint32_t len, sc_tables_len, bitmask_len;
+ int ret = 0, bit;
+ char *tmp_mask;
+ struct lttng_syscall_filter *filter;
+
+ ret = get_user(len, &usyscall_mask->len);
+ if (ret)
+ return ret;
+ sc_tables_len = get_sc_tables_len();
+ bitmask_len = ALIGN(sc_tables_len, 8) >> 3;
+ if (len < sc_tables_len) {
+ return put_user(sc_tables_len, &usyscall_mask->len);
+ }
+ /* Array is large enough, we can copy array to user-space. */
+ tmp_mask = kzalloc(bitmask_len, GFP_KERNEL);
+ if (!tmp_mask)
+ return -ENOMEM;
+ filter = channel->sc_filter;
+
+ for (bit = 0; bit < ARRAY_SIZE(sc_table); bit++) {
+ bool state;
+
+ if (channel->sc_table) {
+ if (filter)
+ state = test_bit(bit, filter->sc);
+ else
+ state = 1;
+ } else {
+ state = 0;
+ }
+ bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
+ }
+ for (; bit < sc_tables_len; bit++) {
+ bool state;
+
+ if (channel->compat_sc_table) {
+ if (filter)
+ state = test_bit(bit - ARRAY_SIZE(sc_table),
+ filter->sc_compat);
+ else
+ state = 1;
+ } else {
+ state = 0;
+ }
+ bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
+ }
+ if (copy_to_user(usyscall_mask->mask, tmp_mask, bitmask_len))
+ ret = -EFAULT;
+ kfree(tmp_mask);
+ return ret;
+}
+
+int lttng_abi_syscall_list(void)
+{
+ struct file *syscall_list_file;
+ int file_fd, ret;
+
+ file_fd = lttng_get_unused_fd();
+ if (file_fd < 0) {
+ ret = file_fd;
+ goto fd_error;
+ }
+
+ syscall_list_file = anon_inode_getfile("[lttng_syscall_list]",
+ <tng_syscall_list_fops,
+ NULL, O_RDWR);
+ if (IS_ERR(syscall_list_file)) {
+ ret = PTR_ERR(syscall_list_file);
+ goto file_error;
+ }
+ ret = lttng_syscall_list_fops.open(NULL, syscall_list_file);
+ if (ret < 0)
+ goto open_error;
+ fd_install(file_fd, syscall_list_file);
+ if (file_fd < 0) {
+ ret = file_fd;
+ goto fd_error;
+ }
+ return file_fd;
+
+open_error:
+ fput(syscall_list_file);
+file_error:
+ put_unused_fd(file_fd);
+fd_error:
+ return ret;
+}