X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=lttng-syscalls.c;h=70d2c323ce9207b191313488a87d80b464075b7b;hb=refs%2Fheads%2Fstable-2.7;hp=5cac721200bb8aa5cab44ffcfa281e380d7ccfe1;hpb=bcde0d5b7da973a9372b3db4acc0b08b9589e05b;p=lttng-modules.git diff --git a/lttng-syscalls.c b/lttng-syscalls.c index 5cac7212..70d2c323 100644 --- a/lttng-syscalls.c +++ b/lttng-syscalls.c @@ -29,11 +29,15 @@ #include #include #include +#include +#include #include #include #include "lib/bitfield.h" #include "wrapper/tracepoint.h" +#include "wrapper/file.h" +#include "wrapper/rcu.h" #include "lttng-events.h" #ifndef CONFIG_COMPAT @@ -42,6 +46,11 @@ # endif #endif +/* in_compat_syscall appears in kernel 4.6. */ +#ifndef in_compat_syscall + #define in_compat_syscall() is_compat_task() +#endif + enum sc_type { SC_TYPE_ENTRY, SC_TYPE_EXIT, @@ -73,6 +82,7 @@ struct oldold_utsname; struct old_utsname; struct sel_arg_struct; struct mmap_arg_struct; +struct file_handle; #ifdef IA32_NR_syscalls #define NR_compat_syscalls IA32_NR_syscalls @@ -91,6 +101,7 @@ struct mmap_arg_struct; #define PARAMS(args...) args /* Handle unknown syscalls */ +#undef TRACE_SYSTEM #define TRACE_SYSTEM syscalls_unknown #include "instrumentation/syscalls/headers/syscalls_unknown.h" #undef TRACE_SYSTEM @@ -109,16 +120,15 @@ struct mmap_arg_struct; /* Hijack probe callback for system call enter */ #undef TP_PROBE_CB #define TP_PROBE_CB(_template) &syscall_entry_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ LTTNG_TRACEPOINT_EVENT_CODE(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ PARAMS(_locvar), PARAMS(_code), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_entry_##_name, PARAMS(_struct), PARAMS(_assign), \ - PARAMS(_printk)) + PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ + LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_entry_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_entry_##_template, syscall_entry_##_name) #undef TRACE_SYSTEM @@ -142,17 +152,14 @@ struct mmap_arg_struct; /* Hijack probe callback for compat system call enter */ #define TP_PROBE_CB(_template) &syscall_entry_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_struct), PARAMS(_assign), \ - PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_locvar), PARAMS(_code), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_entry_##_name, PARAMS(_struct), \ - PARAMS(_assign), PARAMS(_printk)) + PARAMS(_locvar), PARAMS(_code), PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ + LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_entry_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_entry_##_template, \ compat_syscall_entry_##_name) @@ -189,16 +196,14 @@ struct mmap_arg_struct; /* Hijack probe callback for system call exit */ #define TP_PROBE_CB(_template) &syscall_exit_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ LTTNG_TRACEPOINT_EVENT_CODE(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_locvar), PARAMS(_code), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_struct), \ - PARAMS(_assign), PARAMS(_printk)) + PARAMS(_locvar), PARAMS(_code), PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ + LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_exit_##_template, \ syscall_exit_##_name) @@ -223,16 +228,14 @@ struct mmap_arg_struct; /* Hijack probe callback for compat system call exit */ #define TP_PROBE_CB(_template) &syscall_exit_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_locvar), PARAMS(_code), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_struct), \ - PARAMS(_assign), PARAMS(_printk)) + PARAMS(_locvar), PARAMS(_code), PARAMS(_fields)) +#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ + LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_exit_##_template, \ compat_syscall_exit_##_name) @@ -356,7 +359,7 @@ static void syscall_entry_unknown(struct lttng_event *event, unsigned long args[UNKNOWN_SYSCALL_NRARGS]; syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args); - if (unlikely(is_compat_task())) + if (unlikely(in_compat_syscall())) __event_probe__compat_syscall_entry_unknown(event, id, args); else __event_probe__syscall_entry_unknown(event, id, args); @@ -369,12 +372,12 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) const struct trace_syscall_entry *table, *entry; size_t table_len; - if (unlikely(is_compat_task())) { + if (unlikely(in_compat_syscall())) { struct lttng_syscall_filter *filter; - filter = rcu_dereference(chan->sc_filter); + filter = lttng_rcu_dereference(chan->sc_filter); if (filter) { - if (id >= NR_compat_syscalls + if (id < 0 || id >= NR_compat_syscalls || !test_bit(id, filter->sc_compat)) { /* System call filtered out. */ return; @@ -386,9 +389,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) } else { struct lttng_syscall_filter *filter; - filter = rcu_dereference(chan->sc_filter); + filter = lttng_rcu_dereference(chan->sc_filter); if (filter) { - if (id >= NR_syscalls + if (id < 0 || id >= NR_syscalls || !test_bit(id, filter->sc)) { /* System call filtered out. */ return; @@ -398,11 +401,11 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) table_len = ARRAY_SIZE(sc_table); unknown_event = chan->sc_unknown; } - if (unlikely(id >= table_len)) { + if (unlikely(id < 0 || id >= table_len)) { syscall_entry_unknown(unknown_event, regs, id); return; } - if (unlikely(is_compat_task())) + if (unlikely(in_compat_syscall())) event = chan->compat_sc_table[id]; else event = chan->sc_table[id]; @@ -502,12 +505,12 @@ 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, unsigned int id, long ret) + struct pt_regs *regs, int id, long ret) { unsigned long args[UNKNOWN_SYSCALL_NRARGS]; syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args); - if (unlikely(is_compat_task())) + if (unlikely(in_compat_syscall())) __event_probe__compat_syscall_exit_unknown(event, id, ret, args); else @@ -523,12 +526,12 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) long id; id = syscall_get_nr(current, regs); - if (unlikely(is_compat_task())) { + if (unlikely(in_compat_syscall())) { struct lttng_syscall_filter *filter; - filter = rcu_dereference(chan->sc_filter); + filter = lttng_rcu_dereference(chan->sc_filter); if (filter) { - if (id >= NR_compat_syscalls + if (id < 0 || id >= NR_compat_syscalls || !test_bit(id, filter->sc_compat)) { /* System call filtered out. */ return; @@ -540,9 +543,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) } else { struct lttng_syscall_filter *filter; - filter = rcu_dereference(chan->sc_filter); + filter = lttng_rcu_dereference(chan->sc_filter); if (filter) { - if (id >= NR_syscalls + if (id < 0 || id >= NR_syscalls || !test_bit(id, filter->sc)) { /* System call filtered out. */ return; @@ -552,11 +555,11 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) table_len = ARRAY_SIZE(sc_exit_table); unknown_event = chan->sc_exit_unknown; } - if (unlikely(id >= table_len)) { + if (unlikely(id < 0 || id >= table_len)) { syscall_exit_unknown(unknown_event, regs, id, ret); return; } - if (unlikely(is_compat_task())) + if (unlikely(in_compat_syscall())) event = chan->compat_sc_exit_table[id]; else event = chan->sc_exit_table[id]; @@ -662,7 +665,10 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) } } -/* noinline to diminish caller stack size */ +/* + * 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, @@ -711,9 +717,9 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len, strncat(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan_table[i] = lttng_event_create(chan, &ev, filter, - desc); + 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])) { /* @@ -728,6 +734,9 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len, return 0; } +/* + * Should be called with sessions lock held. + */ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) { struct lttng_kernel_event ev; @@ -775,9 +784,10 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->sc_unknown = lttng_event_create(chan, &ev, filter, - desc); + ev.instrumentation = LTTNG_KERNEL_SYSCALL; + 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); @@ -791,9 +801,10 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter, - desc); + ev.instrumentation = LTTNG_KERNEL_SYSCALL; + 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); @@ -807,9 +818,10 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->compat_sc_exit_unknown = lttng_event_create(chan, &ev, - filter, desc); + ev.instrumentation = LTTNG_KERNEL_SYSCALL; + 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); @@ -823,9 +835,9 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->sc_exit_unknown = lttng_event_create(chan, &ev, filter, - desc); + ev.instrumentation = LTTNG_KERNEL_SYSCALL; + 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); @@ -1229,16 +1241,66 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel, filter = channel->sc_filter; for (bit = 0; bit < ARRAY_SIZE(sc_table); bit++) { - bt_bitfield_write_be(tmp_mask, char, bit, 1, - test_bit(bit, filter->sc)); + 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++) { - bt_bitfield_write_be(tmp_mask, char, bit, 1, - test_bit(bit - ARRAY_SIZE(sc_table), - filter->sc_compat)); + 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); + return file_fd; + +open_error: + fput(syscall_list_file); +file_error: + put_unused_fd(file_fd); +fd_error: + return ret; +}