Fix: cpu-id context should use int type
[lttng-modules.git] / lttng-events.c
index 3616e010410134ee3021260cbf3d7de1bb018610..7eec04c0f269682a1aed08bbc501a9a992a127ea 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/*
+ * This page_alloc.h wrapper needs to be included before gfpflags.h because it
+ * overrides a function with a define.
+ */
+#include "wrapper/page_alloc.h"
+
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
@@ -32,6 +38,7 @@
 #include <linux/anon_inodes.h>
 #include "wrapper/file.h"
 #include <linux/jhash.h>
+#include <linux/uaccess.h>
 
 #include "wrapper/uuid.h"
 #include "wrapper/vmalloc.h"   /* for wrapper_vmalloc_sync_all() */
@@ -481,6 +488,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan,
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
        case LTTNG_KERNEL_NOOP:
+       case LTTNG_KERNEL_SYSCALL:
                event_name = event_param->name;
                break;
        default:
@@ -491,7 +499,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan,
        name_len = strlen(event_name);
        hash = jhash(event_name, name_len, 0);
        head = &session->events_ht.table[hash & (LTTNG_EVENT_HT_SIZE - 1)];
-       hlist_for_each_entry(event, head, hlist) {
+       lttng_hlist_for_each_entry(event, head, hlist) {
                WARN_ON_ONCE(!event->desc);
                if (!strncmp(event->desc->name, event_name,
                                        LTTNG_KERNEL_SYM_NAME_LEN - 1)
@@ -511,6 +519,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan,
        event->id = chan->free_event_id++;
        event->instrumentation = itype;
        event->evtype = LTTNG_TYPE_EVENT;
+       INIT_LIST_HEAD(&event->bytecode_runtime_head);
        INIT_LIST_HEAD(&event->enablers_ref_head);
 
        switch (itype) {
@@ -614,6 +623,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan,
                WARN_ON_ONCE(!ret);
                break;
        case LTTNG_KERNEL_NOOP:
+       case LTTNG_KERNEL_SYSCALL:
                event->enabled = 1;
                event->registered = 0;
                event->desc = event_desc;
@@ -634,7 +644,6 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan,
        }
        hlist_add_head(&event->hlist, head);
        list_add(&event->list, &chan->session->events);
-       mutex_unlock(&sessions_mutex);
        return event;
 
 statedump_error:
@@ -668,14 +677,31 @@ static
 void register_event(struct lttng_event *event)
 {
        const struct lttng_event_desc *desc;
-       int ret;
+       int ret = -EINVAL;
 
-       WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_TRACEPOINT);
        if (event->registered)
                return;
+
        desc = event->desc;
-       ret = lttng_wrapper_tracepoint_probe_register(desc->kname,
-               desc->probe_callback, event);
+       switch (event->instrumentation) {
+       case LTTNG_KERNEL_TRACEPOINT:
+               ret = lttng_wrapper_tracepoint_probe_register(desc->kname,
+                                                 desc->probe_callback,
+                                                 event);
+               break;
+       case LTTNG_KERNEL_SYSCALL:
+               ret = lttng_syscall_filter_enable(event->chan,
+                       desc->name);
+               break;
+       case LTTNG_KERNEL_KPROBE:
+       case LTTNG_KERNEL_KRETPROBE:
+       case LTTNG_KERNEL_FUNCTION:
+       case LTTNG_KERNEL_NOOP:
+               ret = 0;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
        if (!ret)
                event->registered = 1;
 }
@@ -685,18 +711,18 @@ void register_event(struct lttng_event *event)
  */
 int _lttng_event_unregister(struct lttng_event *event)
 {
+       const struct lttng_event_desc *desc;
        int ret = -EINVAL;
 
        if (!event->registered)
                return 0;
 
+       desc = event->desc;
        switch (event->instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
                ret = lttng_wrapper_tracepoint_probe_unregister(event->desc->kname,
                                                  event->desc->probe_callback,
                                                  event);
-               if (ret)
-                       return ret;
                break;
        case LTTNG_KERNEL_KPROBE:
                lttng_kprobes_unregister(event);
@@ -710,6 +736,10 @@ int _lttng_event_unregister(struct lttng_event *event)
                lttng_ftrace_unregister(event);
                ret = 0;
                break;
+       case LTTNG_KERNEL_SYSCALL:
+               ret = lttng_syscall_filter_disable(event->chan,
+                       desc->name);
+               break;
        case LTTNG_KERNEL_NOOP:
                ret = 0;
                break;
@@ -744,6 +774,7 @@ void _lttng_event_destroy(struct lttng_event *event)
                lttng_ftrace_destroy_private(event);
                break;
        case LTTNG_KERNEL_NOOP:
+       case LTTNG_KERNEL_SYSCALL:
                break;
        default:
                WARN_ON_ONCE(1);
@@ -986,23 +1017,20 @@ fd_error:
  * Enabler management.
  */
 static
-int lttng_desc_match_wildcard_enabler(const struct lttng_event_desc *desc,
-               struct lttng_enabler *enabler)
+int lttng_match_enabler_wildcard(const char *desc_name,
+               const char *name)
 {
-       WARN_ON_ONCE(enabler->type != LTTNG_ENABLER_WILDCARD);
        /* Compare excluding final '*' */
-       if (strncmp(desc->name, enabler->event_param.name,
-                       strlen(enabler->event_param.name) - 1))
+       if (strncmp(desc_name, name, strlen(name) - 1))
                return 0;
        return 1;
 }
 
 static
-int lttng_desc_match_name_enabler(const struct lttng_event_desc *desc,
-               struct lttng_enabler *enabler)
+int lttng_match_enabler_name(const char *desc_name,
+               const char *name)
 {
-       WARN_ON_ONCE(enabler->type != LTTNG_ENABLER_NAME);
-       if (strcmp(desc->name, enabler->event_param.name))
+       if (strcmp(desc_name, name))
                return 0;
        return 1;
 }
@@ -1011,11 +1039,37 @@ static
 int lttng_desc_match_enabler(const struct lttng_event_desc *desc,
                struct lttng_enabler *enabler)
 {
+       const char *desc_name, *enabler_name;
+
+       enabler_name = enabler->event_param.name;
+       switch (enabler->event_param.instrumentation) {
+       case LTTNG_KERNEL_TRACEPOINT:
+               desc_name = desc->name;
+               break;
+       case LTTNG_KERNEL_SYSCALL:
+               desc_name = desc->name;
+               if (!strncmp(desc_name, "compat_", strlen("compat_")))
+                       desc_name += strlen("compat_");
+               if (!strncmp(desc_name, "syscall_exit_",
+                               strlen("syscall_exit_"))) {
+                       desc_name += strlen("syscall_exit_");
+               } else if (!strncmp(desc_name, "syscall_entry_",
+                               strlen("syscall_entry_"))) {
+                       desc_name += strlen("syscall_entry_");
+               } else {
+                       WARN_ON_ONCE(1);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
        switch (enabler->type) {
        case LTTNG_ENABLER_WILDCARD:
-               return lttng_desc_match_wildcard_enabler(desc, enabler);
+               return lttng_match_enabler_wildcard(desc_name, enabler_name);
        case LTTNG_ENABLER_NAME:
-               return lttng_desc_match_name_enabler(desc, enabler);
+               return lttng_match_enabler_name(desc_name, enabler_name);
        default:
                return -EINVAL;
        }
@@ -1025,6 +1079,8 @@ static
 int lttng_event_match_enabler(struct lttng_event *event,
                struct lttng_enabler *enabler)
 {
+       if (enabler->event_param.instrumentation != event->instrumentation)
+               return 0;
        if (lttng_desc_match_enabler(event->desc, enabler)
                        && event->chan == enabler->chan)
                return 1;
@@ -1046,13 +1102,8 @@ struct lttng_enabler_ref *lttng_event_enabler_ref(struct lttng_event *event,
        return NULL;
 }
 
-/*
- * Create struct lttng_event if it is missing and present in the list of
- * tracepoint probes.
- * Should be called with sessions mutex held.
- */
 static
-void lttng_create_event_if_missing(struct lttng_enabler *enabler)
+void lttng_create_tracepoint_if_missing(struct lttng_enabler *enabler)
 {
        struct lttng_session *session = enabler->chan->session;
        struct lttng_probe_desc *probe_desc;
@@ -1086,7 +1137,7 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler)
                         */
                        hash = jhash(event_name, name_len, 0);
                        head = &session->events_ht.table[hash & (LTTNG_EVENT_HT_SIZE - 1)];
-                       hlist_for_each_entry(event, head, hlist) {
+                       lttng_hlist_for_each_entry(event, head, hlist) {
                                if (event->desc == desc
                                                && event->chan == enabler->chan)
                                        found = 1;
@@ -1109,6 +1160,36 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler)
        }
 }
 
+static
+void lttng_create_syscall_if_missing(struct lttng_enabler *enabler)
+{
+       int ret;
+
+       ret = lttng_syscalls_register(enabler->chan, NULL);
+       WARN_ON_ONCE(ret);
+}
+
+/*
+ * Create struct lttng_event if it is missing and present in the list of
+ * tracepoint probes.
+ * Should be called with sessions mutex held.
+ */
+static
+void lttng_create_event_if_missing(struct lttng_enabler *enabler)
+{
+       switch (enabler->event_param.instrumentation) {
+       case LTTNG_KERNEL_TRACEPOINT:
+               lttng_create_tracepoint_if_missing(enabler);
+               break;
+       case LTTNG_KERNEL_SYSCALL:
+               lttng_create_syscall_if_missing(enabler);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               break;
+       }
+}
+
 /*
  * Create events associated with an enabler (if not already present),
  * and add backward reference from the event to the enabler.
@@ -1143,6 +1224,11 @@ int lttng_enabler_ref_events(struct lttng_enabler *enabler)
                                &event->enablers_ref_head);
                }
 
+               /*
+                * Link filter bytecodes if not linked yet.
+                */
+               lttng_enabler_event_link_bytecode(event, enabler);
+
                /* TODO: merge event context. */
        }
        return 0;
@@ -1172,11 +1258,12 @@ struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type,
        if (!enabler)
                return NULL;
        enabler->type = type;
+       INIT_LIST_HEAD(&enabler->filter_bytecode_head);
        memcpy(&enabler->event_param, event_param,
                sizeof(enabler->event_param));
        enabler->chan = chan;
        /* ctx left NULL */
-       enabler->enabled = 1;
+       enabler->enabled = 0;
        enabler->evtype = LTTNG_TYPE_ENABLER;
        mutex_lock(&sessions_mutex);
        list_add(&enabler->node, &enabler->chan->session->enablers_head);
@@ -1203,6 +1290,36 @@ int lttng_enabler_disable(struct lttng_enabler *enabler)
        return 0;
 }
 
+int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
+               struct lttng_kernel_filter_bytecode __user *bytecode)
+{
+       struct lttng_filter_bytecode_node *bytecode_node;
+       uint32_t bytecode_len;
+       int ret;
+
+       ret = get_user(bytecode_len, &bytecode->len);
+       if (ret)
+               return ret;
+       bytecode_node = kzalloc(sizeof(*bytecode_node) + bytecode_len,
+                       GFP_KERNEL);
+       if (!bytecode_node)
+               return -ENOMEM;
+       ret = copy_from_user(&bytecode_node->bc, bytecode,
+               sizeof(*bytecode) + bytecode_len);
+       if (ret)
+               goto error_free;
+       bytecode_node->enabler = enabler;
+       /* Enforce length based on allocated size */
+       bytecode_node->bc.len = bytecode_len;
+       list_add_tail(&bytecode_node->node, &enabler->filter_bytecode_head);
+       lttng_session_lazy_sync_enablers(enabler->chan->session);
+       return 0;
+
+error_free:
+       kfree(bytecode_node);
+       return ret;
+}
+
 int lttng_enabler_attach_context(struct lttng_enabler *enabler,
                struct lttng_kernel_context *context_param)
 {
@@ -1212,6 +1329,14 @@ int lttng_enabler_attach_context(struct lttng_enabler *enabler,
 static
 void lttng_enabler_destroy(struct lttng_enabler *enabler)
 {
+       struct lttng_filter_bytecode_node *filter_node, *tmp_filter_node;
+
+       /* Destroy filter bytecode */
+       list_for_each_entry_safe(filter_node, tmp_filter_node,
+                       &enabler->filter_bytecode_head, node) {
+               kfree(filter_node);
+       }
+
        /* Destroy contexts */
        lttng_destroy_context(enabler->ctx);
 
@@ -1239,9 +1364,12 @@ void lttng_session_sync_enablers(struct lttng_session *session)
         */
        list_for_each_entry(event, &session->events, list) {
                struct lttng_enabler_ref *enabler_ref;
-               int enabled = 0;
+               struct lttng_bytecode_runtime *runtime;
+               int enabled = 0, has_enablers_without_bytecode = 0;
 
-               if (event->instrumentation == LTTNG_KERNEL_TRACEPOINT) {
+               switch (event->instrumentation) {
+               case LTTNG_KERNEL_TRACEPOINT:
+               case LTTNG_KERNEL_SYSCALL:
                        /* Enable events */
                        list_for_each_entry(enabler_ref,
                                        &event->enablers_ref_head, node) {
@@ -1250,7 +1378,8 @@ void lttng_session_sync_enablers(struct lttng_session *session)
                                        break;
                                }
                        }
-               } else {
+                       break;
+               default:
                        /* Not handled with lazy sync. */
                        continue;
                }
@@ -1271,6 +1400,23 @@ void lttng_session_sync_enablers(struct lttng_session *session)
                } else {
                        _lttng_event_unregister(event);
                }
+
+               /* Check if has enablers without bytecode enabled */
+               list_for_each_entry(enabler_ref,
+                               &event->enablers_ref_head, node) {
+                       if (enabler_ref->ref->enabled
+                                       && list_empty(&enabler_ref->ref->filter_bytecode_head)) {
+                               has_enablers_without_bytecode = 1;
+                               break;
+                       }
+               }
+               event->has_enablers_without_bytecode =
+                       has_enablers_without_bytecode;
+
+               /* Enable filters */
+               list_for_each_entry(runtime,
+                               &event->bytecode_runtime_head, node)
+                       lttng_filter_sync_state(runtime);
        }
 }
 
@@ -1975,10 +2121,15 @@ static int __init lttng_events_init(void)
        ret = wrapper_lttng_fixup_sig(THIS_MODULE);
        if (ret)
                return ret;
-
-       ret = lttng_tracepoint_init();
+       ret = wrapper_get_pfnblock_flags_mask_init();
+       if (ret)
+               return ret;
+       ret = lttng_context_init();
        if (ret)
                return ret;
+       ret = lttng_tracepoint_init();
+       if (ret)
+               goto error_tp;
        event_cache = KMEM_CACHE(lttng_event, 0);
        if (!event_cache) {
                ret = -ENOMEM;
@@ -1998,6 +2149,8 @@ error_abi:
        kmem_cache_destroy(event_cache);
 error_kmem:
        lttng_tracepoint_exit();
+error_tp:
+       lttng_context_exit();
        return ret;
 }
 
@@ -2013,6 +2166,7 @@ static void __exit lttng_events_exit(void)
                lttng_session_destroy(session);
        kmem_cache_destroy(event_cache);
        lttng_tracepoint_exit();
+       lttng_context_exit();
 }
 
 module_exit(lttng_events_exit);
This page took 0.028262 seconds and 4 git commands to generate.