#include <wrapper/file.h>
#include <wrapper/rcu.h>
#include <wrapper/syscall.h>
+#include <wrapper/limits.h>
#include <lttng/events.h>
#include <lttng/events-internal.h>
#include <lttng/utils.h>
+#include <lttng/kernel-version.h>
#include "lttng-syscalls.h"
/* in_compat_syscall appears in kernel 4.6. */
#ifndef in_compat_syscall
- #define in_compat_syscall() is_compat_task()
+# define in_compat_syscall() is_compat_task()
+#endif
+
+/* in_x32_syscall appears in kernel 4.7. */
+#if (LTTNG_LINUX_VERSION_CODE < LTTNG_KERNEL_VERSION(4,7,0))
+# ifdef CONFIG_X86_X32_ABI
+# define in_x32_syscall() is_x32_task()
+# endif
#endif
enum sc_type {
DECLARE_BITMAP(sc_exit, NR_syscalls);
DECLARE_BITMAP(sc_compat_entry, NR_compat_syscalls);
DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls);
+
+ /*
+ * Reference counters keeping track of number of events enabled
+ * for each bit.
+ */
+ u32 sc_entry_refcount_map[NR_syscalls];
+ u32 sc_exit_refcount_map[NR_syscalls];
+ u32 sc_compat_entry_refcount_map[NR_compat_syscalls];
+ u32 sc_compat_exit_refcount_map[NR_compat_syscalls];
};
static void syscall_entry_event_unknown(struct hlist_head *unknown_action_list_head,
const struct trace_syscall_entry *table, *entry;
size_t table_len;
+#ifdef CONFIG_X86_X32_ABI
+ if (in_x32_syscall()) {
+ /* x32 system calls are not supported. */
+ return;
+ }
+#endif
if (unlikely(in_compat_syscall())) {
struct lttng_syscall_filter *filter = chan->priv->parent.sc_filter;
size_t table_len;
long id;
+#ifdef CONFIG_X86_X32_ABI
+ if (in_x32_syscall()) {
+ /* x32 system calls are not supported. */
+ return;
+ }
+#endif
id = syscall_get_nr(current, regs);
if (unlikely(in_compat_syscall())) {
{
const char *syscall_name;
unsigned long *bitmap;
+ u32 *refcount_map;
int syscall_nr;
syscall_name = get_syscall_name(desc_name, abi, entryexit);
switch (abi) {
case LTTNG_SYSCALL_ABI_NATIVE:
bitmap = filter->sc_entry;
+ refcount_map = filter->sc_entry_refcount_map;
break;
case LTTNG_SYSCALL_ABI_COMPAT:
bitmap = filter->sc_compat_entry;
+ refcount_map = filter->sc_compat_entry_refcount_map;
break;
default:
return -EINVAL;
switch (abi) {
case LTTNG_SYSCALL_ABI_NATIVE:
bitmap = filter->sc_exit;
+ refcount_map = filter->sc_exit_refcount_map;
break;
case LTTNG_SYSCALL_ABI_COMPAT:
bitmap = filter->sc_compat_exit;
+ refcount_map = filter->sc_compat_exit_refcount_map;
break;
default:
return -EINVAL;
default:
return -EINVAL;
}
- if (test_bit(syscall_nr, bitmap))
- return -EEXIST;
- bitmap_set(bitmap, syscall_nr, 1);
+ if (refcount_map[syscall_nr] == U32_MAX)
+ return -EOVERFLOW;
+ if (refcount_map[syscall_nr]++ == 0)
+ bitmap_set(bitmap, syscall_nr, 1);
return 0;
}
WARN_ON_ONCE(event_notifier->priv->parent.instrumentation != LTTNG_KERNEL_ABI_SYSCALL);
+ /* Skip unknown syscall */
+ if (syscall_id == -1U)
+ return 0;
+
ret = lttng_syscall_filter_enable(group->sc_filter,
event_notifier->priv->parent.desc->event_name,
event_notifier->priv->parent.u.syscall.abi,
event_notifier->priv->parent.u.syscall.entryexit);
- if (ret) {
- goto end;
- }
+ if (ret)
+ return ret;
switch (event_notifier->priv->parent.u.syscall.entryexit) {
case LTTNG_SYSCALL_ENTRY:
hlist_add_head_rcu(&event_notifier->priv->parent.u.syscall.node, dispatch_list);
end:
- return ret ;
+ return ret;
}
int lttng_syscall_filter_enable_event(
struct lttng_kernel_channel_buffer *channel,
struct lttng_kernel_event_recorder *event_recorder)
{
+ unsigned int syscall_id = event_recorder->priv->parent.u.syscall.syscall_id;
+
WARN_ON_ONCE(event_recorder->priv->parent.instrumentation != LTTNG_KERNEL_ABI_SYSCALL);
+ /* Skip unknown syscall */
+ if (syscall_id == -1U)
+ return 0;
+
return lttng_syscall_filter_enable(channel->priv->parent.sc_filter,
event_recorder->priv->parent.desc->event_name,
event_recorder->priv->parent.u.syscall.abi,
{
const char *syscall_name;
unsigned long *bitmap;
+ u32 *refcount_map;
int syscall_nr;
syscall_name = get_syscall_name(desc_name, abi, entryexit);
switch (abi) {
case LTTNG_SYSCALL_ABI_NATIVE:
bitmap = filter->sc_entry;
+ refcount_map = filter->sc_entry_refcount_map;
break;
case LTTNG_SYSCALL_ABI_COMPAT:
bitmap = filter->sc_compat_entry;
+ refcount_map = filter->sc_compat_entry_refcount_map;
break;
default:
return -EINVAL;
switch (abi) {
case LTTNG_SYSCALL_ABI_NATIVE:
bitmap = filter->sc_exit;
+ refcount_map = filter->sc_exit_refcount_map;
break;
case LTTNG_SYSCALL_ABI_COMPAT:
bitmap = filter->sc_compat_exit;
+ refcount_map = filter->sc_compat_exit_refcount_map;
break;
default:
return -EINVAL;
default:
return -EINVAL;
}
- if (!test_bit(syscall_nr, bitmap))
- return -EEXIST;
- bitmap_clear(bitmap, syscall_nr, 1);
-
+ if (refcount_map[syscall_nr] == 0)
+ return -ENOENT;
+ if (--refcount_map[syscall_nr] == 0)
+ bitmap_clear(bitmap, syscall_nr, 1);
return 0;
}
struct lttng_kernel_event_notifier *event_notifier)
{
struct lttng_event_notifier_group *group = event_notifier->priv->group;
+ unsigned int syscall_id = event_notifier->priv->parent.u.syscall.syscall_id;
int ret;
WARN_ON_ONCE(event_notifier->priv->parent.instrumentation != LTTNG_KERNEL_ABI_SYSCALL);
+ /* Skip unknown syscall */
+ if (syscall_id == -1U)
+ return 0;
+
ret = lttng_syscall_filter_disable(group->sc_filter,
event_notifier->priv->parent.desc->event_name,
event_notifier->priv->parent.u.syscall.abi,
event_notifier->priv->parent.u.syscall.entryexit);
- WARN_ON_ONCE(ret != 0);
+ if (ret)
+ return ret;
hlist_del_rcu(&event_notifier->priv->parent.u.syscall.node);
return 0;
struct lttng_kernel_channel_buffer *channel,
struct lttng_kernel_event_recorder *event_recorder)
{
+ unsigned int syscall_id = event_recorder->priv->parent.u.syscall.syscall_id;
+
+ /* Skip unknown syscall */
+ if (syscall_id == -1U)
+ return 0;
+
return lttng_syscall_filter_disable(channel->priv->parent.sc_filter,
event_recorder->priv->parent.desc->event_name,
event_recorder->priv->parent.u.syscall.abi,