]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - kernel/trace/trace_uprobe.c
Merge tag 'libnvdimm-fixes-5.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / kernel / trace / trace_uprobe.c
index b55906c77ce0602ad6d7f0c20225e99f288ddbb9..1ceedb9146b114e6225a7662044c6b00c4cba136 100644 (file)
@@ -140,6 +140,13 @@ probe_mem_read(void *dest, void *src, size_t size)
 
        return copy_from_user(dest, vaddr, size) ? -EFAULT : 0;
 }
+
+static nokprobe_inline int
+probe_mem_read_user(void *dest, void *src, size_t size)
+{
+       return probe_mem_read(dest, src, size);
+}
+
 /*
  * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
  * length and relative data location.
@@ -176,6 +183,12 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
        return ret;
 }
 
+static nokprobe_inline int
+fetch_store_string_user(unsigned long addr, void *dest, void *base)
+{
+       return fetch_store_string(addr, dest, base);
+}
+
 /* Return the length of string -- including null terminal byte */
 static nokprobe_inline int
 fetch_store_strlen(unsigned long addr)
@@ -191,6 +204,12 @@ fetch_store_strlen(unsigned long addr)
        return (len > MAX_STRING_SIZE) ? 0 : len;
 }
 
+static nokprobe_inline int
+fetch_store_strlen_user(unsigned long addr)
+{
+       return fetch_store_strlen(addr);
+}
+
 static unsigned long translate_user_vaddr(unsigned long file_offset)
 {
        unsigned long base_addr;
@@ -270,8 +289,8 @@ static bool trace_uprobe_match(const char *system, const char *event,
 {
        struct trace_uprobe *tu = to_trace_uprobe(ev);
 
-       return strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
-               (!system || strcmp(tu->tp.call.class->system, system) == 0);
+       return strcmp(trace_probe_name(&tu->tp), event) == 0 &&
+           (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
 }
 
 /*
@@ -281,25 +300,17 @@ static struct trace_uprobe *
 alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
 {
        struct trace_uprobe *tu;
-
-       if (!event || !group)
-               return ERR_PTR(-EINVAL);
+       int ret;
 
        tu = kzalloc(SIZEOF_TRACE_UPROBE(nargs), GFP_KERNEL);
        if (!tu)
                return ERR_PTR(-ENOMEM);
 
-       tu->tp.call.class = &tu->tp.class;
-       tu->tp.call.name = kstrdup(event, GFP_KERNEL);
-       if (!tu->tp.call.name)
-               goto error;
-
-       tu->tp.class.system = kstrdup(group, GFP_KERNEL);
-       if (!tu->tp.class.system)
+       ret = trace_probe_init(&tu->tp, event, group);
+       if (ret < 0)
                goto error;
 
        dyn_event_init(&tu->devent, &trace_uprobe_ops);
-       INIT_LIST_HEAD(&tu->tp.files);
        tu->consumer.handler = uprobe_dispatcher;
        if (is_ret)
                tu->consumer.ret_handler = uretprobe_dispatcher;
@@ -307,25 +318,18 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
        return tu;
 
 error:
-       kfree(tu->tp.call.name);
        kfree(tu);
 
-       return ERR_PTR(-ENOMEM);
+       return ERR_PTR(ret);
 }
 
 static void free_trace_uprobe(struct trace_uprobe *tu)
 {
-       int i;
-
        if (!tu)
                return;
 
-       for (i = 0; i < tu->tp.nr_args; i++)
-               traceprobe_free_probe_arg(&tu->tp.args[i]);
-
        path_put(&tu->path);
-       kfree(tu->tp.call.class->system);
-       kfree(tu->tp.call.name);
+       trace_probe_cleanup(&tu->tp);
        kfree(tu->filename);
        kfree(tu);
 }
@@ -336,8 +340,8 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
        struct trace_uprobe *tu;
 
        for_each_trace_uprobe(tu, pos)
-               if (strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
-                   strcmp(tu->tp.call.class->system, group) == 0)
+               if (strcmp(trace_probe_name(&tu->tp), event) == 0 &&
+                   strcmp(trace_probe_group_name(&tu->tp), group) == 0)
                        return tu;
 
        return NULL;
@@ -372,8 +376,8 @@ static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new)
        struct trace_uprobe *tmp, *old = NULL;
        struct inode *new_inode = d_real_inode(new->path.dentry);
 
-       old = find_probe_event(trace_event_name(&new->tp.call),
-                               new->tp.call.class->system);
+       old = find_probe_event(trace_probe_name(&new->tp),
+                               trace_probe_group_name(&new->tp));
 
        for_each_trace_uprobe(tmp, pos) {
                if ((old ? old != tmp : true) &&
@@ -578,6 +582,10 @@ static int trace_uprobe_create(int argc, const char **argv)
                        goto error;
        }
 
+       ret = traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu));
+       if (ret < 0)
+               goto error;
+
        ret = register_trace_uprobe(tu);
        if (!ret)
                goto out;
@@ -621,8 +629,8 @@ static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev)
        char c = is_ret_probe(tu) ? 'r' : 'p';
        int i;
 
-       seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, tu->tp.call.class->system,
-                       trace_event_name(&tu->tp.call), tu->filename,
+       seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, trace_probe_group_name(&tu->tp),
+                       trace_probe_name(&tu->tp), tu->filename,
                        (int)(sizeof(void *) * 2), tu->offset);
 
        if (tu->ref_ctr_offset)
@@ -692,7 +700,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v)
 
        tu = to_trace_uprobe(ev);
        seq_printf(m, "  %s %-44s %15lu\n", tu->filename,
-                       trace_event_name(&tu->tp.call), tu->nhit);
+                       trace_probe_name(&tu->tp), tu->nhit);
        return 0;
 }
 
@@ -818,7 +826,7 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
        struct ring_buffer *buffer;
        void *data;
        int size, esize;
-       struct trace_event_call *call = &tu->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tu->tp);
 
        WARN_ON(call != trace_file->event_call);
 
@@ -860,7 +868,7 @@ static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
                return 0;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(link, &tu->tp.files, list)
+       trace_probe_for_each_link_rcu(link, &tu->tp)
                __uprobe_trace_func(tu, 0, regs, ucb, dsize, link->file);
        rcu_read_unlock();
 
@@ -874,7 +882,7 @@ static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
        struct event_file_link *link;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(link, &tu->tp.files, list)
+       trace_probe_for_each_link_rcu(link, &tu->tp)
                __uprobe_trace_func(tu, func, regs, ucb, dsize, link->file);
        rcu_read_unlock();
 }
@@ -893,12 +901,12 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 
        if (is_ret_probe(tu)) {
                trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
-                                trace_event_name(&tu->tp.call),
+                                trace_probe_name(&tu->tp),
                                 entry->vaddr[1], entry->vaddr[0]);
                data = DATAOF_TRACE_ENTRY(entry, true);
        } else {
                trace_seq_printf(s, "%s: (0x%lx)",
-                                trace_event_name(&tu->tp.call),
+                                trace_probe_name(&tu->tp),
                                 entry->vaddr[0]);
                data = DATAOF_TRACE_ENTRY(entry, false);
        }
@@ -921,26 +929,20 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
                   filter_func_t filter)
 {
        bool enabled = trace_probe_is_enabled(&tu->tp);
-       struct event_file_link *link = NULL;
        int ret;
 
        if (file) {
-               if (tu->tp.flags & TP_FLAG_PROFILE)
+               if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
                        return -EINTR;
 
-               link = kmalloc(sizeof(*link), GFP_KERNEL);
-               if (!link)
-                       return -ENOMEM;
-
-               link->file = file;
-               list_add_tail_rcu(&link->list, &tu->tp.files);
-
-               tu->tp.flags |= TP_FLAG_TRACE;
+               ret = trace_probe_add_file(&tu->tp, file);
+               if (ret < 0)
+                       return ret;
        } else {
-               if (tu->tp.flags & TP_FLAG_TRACE)
+               if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
                        return -EINTR;
 
-               tu->tp.flags |= TP_FLAG_PROFILE;
+               trace_probe_set_flag(&tu->tp, TP_FLAG_PROFILE);
        }
 
        WARN_ON(!uprobe_filter_is_empty(&tu->filter));
@@ -970,13 +972,11 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
        uprobe_buffer_disable();
 
  err_flags:
-       if (file) {
-               list_del(&link->list);
-               kfree(link);
-               tu->tp.flags &= ~TP_FLAG_TRACE;
-       } else {
-               tu->tp.flags &= ~TP_FLAG_PROFILE;
-       }
+       if (file)
+               trace_probe_remove_file(&tu->tp, file);
+       else
+               trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
+
        return ret;
 }
 
@@ -987,26 +987,18 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
                return;
 
        if (file) {
-               struct event_file_link *link;
-
-               link = find_event_file_link(&tu->tp, file);
-               if (!link)
+               if (trace_probe_remove_file(&tu->tp, file) < 0)
                        return;
 
-               list_del_rcu(&link->list);
-               /* synchronize with u{,ret}probe_trace_func */
-               synchronize_rcu();
-               kfree(link);
-
-               if (!list_empty(&tu->tp.files))
+               if (trace_probe_is_enabled(&tu->tp))
                        return;
-       }
+       } else
+               trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
 
        WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
        uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
        tu->inode = NULL;
-       tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE;
 
        uprobe_buffer_disable();
 }
@@ -1126,7 +1118,7 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
                               unsigned long func, struct pt_regs *regs,
                               struct uprobe_cpu_buffer *ucb, int dsize)
 {
-       struct trace_event_call *call = &tu->tp.call;
+       struct trace_event_call *call = trace_probe_event_call(&tu->tp);
        struct uprobe_trace_entry_head *entry;
        struct hlist_head *head;
        void *data;
@@ -1279,11 +1271,11 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
        ucb = uprobe_buffer_get();
        store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
-       if (tu->tp.flags & TP_FLAG_TRACE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
                ret |= uprobe_trace_func(tu, regs, ucb, dsize);
 
 #ifdef CONFIG_PERF_EVENTS
-       if (tu->tp.flags & TP_FLAG_PROFILE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
                ret |= uprobe_perf_func(tu, regs, ucb, dsize);
 #endif
        uprobe_buffer_put(ucb);
@@ -1314,11 +1306,11 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
        ucb = uprobe_buffer_get();
        store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
 
-       if (tu->tp.flags & TP_FLAG_TRACE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
                uretprobe_trace_func(tu, func, regs, ucb, dsize);
 
 #ifdef CONFIG_PERF_EVENTS
-       if (tu->tp.flags & TP_FLAG_PROFILE)
+       if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
                uretprobe_perf_func(tu, func, regs, ucb, dsize);
 #endif
        uprobe_buffer_put(ucb);
@@ -1329,57 +1321,28 @@ static struct trace_event_functions uprobe_funcs = {
        .trace          = print_uprobe_event
 };
 
-static inline void init_trace_event_call(struct trace_uprobe *tu,
-                                        struct trace_event_call *call)
+static inline void init_trace_event_call(struct trace_uprobe *tu)
 {
-       INIT_LIST_HEAD(&call->class->fields);
+       struct trace_event_call *call = trace_probe_event_call(&tu->tp);
+
        call->event.funcs = &uprobe_funcs;
        call->class->define_fields = uprobe_event_define_fields;
 
-       call->flags = TRACE_EVENT_FL_UPROBE;
+       call->flags = TRACE_EVENT_FL_UPROBE | TRACE_EVENT_FL_CAP_ANY;
        call->class->reg = trace_uprobe_register;
        call->data = tu;
 }
 
 static int register_uprobe_event(struct trace_uprobe *tu)
 {
-       struct trace_event_call *call = &tu->tp.call;
-       int ret = 0;
-
-       init_trace_event_call(tu, call);
-
-       if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
-               return -ENOMEM;
+       init_trace_event_call(tu);
 
-       ret = register_trace_event(&call->event);
-       if (!ret) {
-               kfree(call->print_fmt);
-               return -ENODEV;
-       }
-
-       ret = trace_add_event_call(call);
-
-       if (ret) {
-               pr_info("Failed to register uprobe event: %s\n",
-                       trace_event_name(call));
-               kfree(call->print_fmt);
-               unregister_trace_event(&call->event);
-       }
-
-       return ret;
+       return trace_probe_register_event_call(&tu->tp);
 }
 
 static int unregister_uprobe_event(struct trace_uprobe *tu)
 {
-       int ret;
-
-       /* tu->event is unregistered in trace_remove_event_call() */
-       ret = trace_remove_event_call(&tu->tp.call);
-       if (ret)
-               return ret;
-       kfree(tu->tp.call.print_fmt);
-       tu->tp.call.print_fmt = NULL;
-       return 0;
+       return trace_probe_unregister_event_call(&tu->tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1419,14 +1382,14 @@ create_local_trace_uprobe(char *name, unsigned long offs,
        tu->path = path;
        tu->ref_ctr_offset = ref_ctr_offset;
        tu->filename = kstrdup(name, GFP_KERNEL);
-       init_trace_event_call(tu, &tu->tp.call);
+       init_trace_event_call(tu);
 
        if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
                ret = -ENOMEM;
                goto error;
        }
 
-       return &tu->tp.call;
+       return trace_probe_event_call(&tu->tp);
 error:
        free_trace_uprobe(tu);
        return ERR_PTR(ret);
@@ -1438,9 +1401,6 @@ void destroy_local_trace_uprobe(struct trace_event_call *event_call)
 
        tu = container_of(event_call, struct trace_uprobe, tp.call);
 
-       kfree(tu->tp.call.print_fmt);
-       tu->tp.call.print_fmt = NULL;
-
        free_trace_uprobe(tu);
 }
 #endif /* CONFIG_PERF_EVENTS */