]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/trace/ftrace.c
tracing: do not allow modifying the ftrace events via the event files
[linux-2.6-omap-h63xx.git] / kernel / trace / ftrace.c
index aee95aea57e4fb8e0ff17377346e1d1b60a2b9b2..d33d306bdcf4648ab9daabeabb803828c4864cb1 100644 (file)
@@ -218,10 +218,8 @@ static void ftrace_update_pid_func(void)
 {
        ftrace_func_t func;
 
-       mutex_lock(&ftrace_lock);
-
        if (ftrace_trace_function == ftrace_stub)
-               goto out;
+               return;
 
        func = ftrace_trace_function;
 
@@ -238,9 +236,6 @@ static void ftrace_update_pid_func(void)
 #else
        __ftrace_trace_function = func;
 #endif
-
- out:
-       mutex_unlock(&ftrace_lock);
 }
 
 /* set when tracing only a pid */
@@ -255,9 +250,9 @@ static struct pid * const ftrace_swapper_pid = &init_struct_pid;
 
 static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly;
 
-struct ftrace_func_hook {
+struct ftrace_func_probe {
        struct hlist_node       node;
-       struct ftrace_hook_ops  *ops;
+       struct ftrace_probe_ops *ops;
        unsigned long           flags;
        unsigned long           ip;
        void                    *data;
@@ -460,8 +455,8 @@ static void ftrace_bug(int failed, unsigned long ip)
 static int
 __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 {
-       unsigned long ip, fl;
        unsigned long ftrace_addr;
+       unsigned long ip, fl;
 
        ftrace_addr = (unsigned long)FTRACE_ADDR;
 
@@ -530,9 +525,9 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 
 static void ftrace_replace_code(int enable)
 {
-       int failed;
        struct dyn_ftrace *rec;
        struct ftrace_page *pg;
+       int failed;
 
        do_for_each_ftrace_rec(pg, rec) {
                /*
@@ -557,8 +552,11 @@ static void ftrace_replace_code(int enable)
                        if ((system_state == SYSTEM_BOOTING) ||
                            !core_kernel_text(rec->ip)) {
                                ftrace_free_rec(rec);
-                       } else
+                               } else {
                                ftrace_bug(failed, rec->ip);
+                                       /* Stop processing */
+                                       return;
+                               }
                }
        } while_for_each_ftrace_rec();
 }
@@ -580,6 +578,24 @@ ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
        return 1;
 }
 
+/*
+ * archs can override this function if they must do something
+ * before the modifying code is performed.
+ */
+int __weak ftrace_arch_code_modify_prepare(void)
+{
+       return 0;
+}
+
+/*
+ * archs can override this function if they must do something
+ * after the modifying code is performed.
+ */
+int __weak ftrace_arch_code_modify_post_process(void)
+{
+       return 0;
+}
+
 static int __ftrace_modify_code(void *data)
 {
        int *command = data;
@@ -602,7 +618,17 @@ static int __ftrace_modify_code(void *data)
 
 static void ftrace_run_update_code(int command)
 {
+       int ret;
+
+       ret = ftrace_arch_code_modify_prepare();
+       FTRACE_WARN_ON(ret);
+       if (ret)
+               return;
+
        stop_machine(__ftrace_modify_code, &command, NULL);
+
+       ret = ftrace_arch_code_modify_post_process();
+       FTRACE_WARN_ON(ret);
 }
 
 static ftrace_func_t saved_ftrace_func;
@@ -830,11 +856,11 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos)
 
 static int t_hash_show(struct seq_file *m, void *v)
 {
-       struct ftrace_func_hook *rec;
+       struct ftrace_func_probe *rec;
        struct hlist_node *hnd = v;
        char str[KSYM_SYMBOL_LEN];
 
-       rec = hlist_entry(hnd, struct ftrace_func_hook, node);
+       rec = hlist_entry(hnd, struct ftrace_func_probe, node);
 
        if (rec->ops->print)
                return rec->ops->print(m, rec->ip, rec->ops, rec->data);
@@ -1208,14 +1234,15 @@ ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type)
 
 static void ftrace_match_records(char *buff, int len, int enable)
 {
-       char *search;
+       unsigned int search_len;
        struct ftrace_page *pg;
        struct dyn_ftrace *rec;
+       unsigned long flag;
+       char *search;
        int type;
-       unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
-       unsigned search_len;
        int not;
 
+       flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
        type = ftrace_setup_glob(buff, len, &search, &not);
 
        search_len = strlen(search);
@@ -1263,14 +1290,16 @@ ftrace_match_module_record(struct dyn_ftrace *rec, char *mod,
 
 static void ftrace_match_module_records(char *buff, char *mod, int enable)
 {
-       char *search = buff;
+       unsigned search_len = 0;
        struct ftrace_page *pg;
        struct dyn_ftrace *rec;
        int type = MATCH_FULL;
-       unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
-       unsigned search_len = 0;
+       char *search = buff;
+       unsigned long flag;
        int not = 0;
 
+       flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
+
        /* blank or '*' mean the same */
        if (strcmp(buff, "*") == 0)
                buff[0] = 0;
@@ -1348,9 +1377,9 @@ static int __init ftrace_mod_cmd_init(void)
 device_initcall(ftrace_mod_cmd_init);
 
 static void
-function_trace_hook_call(unsigned long ip, unsigned long parent_ip)
+function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
 {
-       struct ftrace_func_hook *entry;
+       struct ftrace_func_probe *entry;
        struct hlist_head *hhd;
        struct hlist_node *n;
        unsigned long key;
@@ -1376,18 +1405,18 @@ function_trace_hook_call(unsigned long ip, unsigned long parent_ip)
        ftrace_preempt_enable(resched);
 }
 
-static struct ftrace_ops trace_hook_ops __read_mostly =
+static struct ftrace_ops trace_probe_ops __read_mostly =
 {
-       .func = function_trace_hook_call,
+       .func = function_trace_probe_call,
 };
 
-static int ftrace_hook_registered;
+static int ftrace_probe_registered;
 
-static void __enable_ftrace_function_hook(void)
+static void __enable_ftrace_function_probe(void)
 {
        int i;
 
-       if (ftrace_hook_registered)
+       if (ftrace_probe_registered)
                return;
 
        for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
@@ -1399,16 +1428,16 @@ static void __enable_ftrace_function_hook(void)
        if (i == FTRACE_FUNC_HASHSIZE)
                return;
 
-       __register_ftrace_function(&trace_hook_ops);
+       __register_ftrace_function(&trace_probe_ops);
        ftrace_startup(0);
-       ftrace_hook_registered = 1;
+       ftrace_probe_registered = 1;
 }
 
-static void __disable_ftrace_function_hook(void)
+static void __disable_ftrace_function_probe(void)
 {
        int i;
 
-       if (!ftrace_hook_registered)
+       if (!ftrace_probe_registered)
                return;
 
        for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
@@ -1418,16 +1447,16 @@ static void __disable_ftrace_function_hook(void)
        }
 
        /* no more funcs left */
-       __unregister_ftrace_function(&trace_hook_ops);
+       __unregister_ftrace_function(&trace_probe_ops);
        ftrace_shutdown(0);
-       ftrace_hook_registered = 0;
+       ftrace_probe_registered = 0;
 }
 
 
 static void ftrace_free_entry_rcu(struct rcu_head *rhp)
 {
-       struct ftrace_func_hook *entry =
-               container_of(rhp, struct ftrace_func_hook, rcu);
+       struct ftrace_func_probe *entry =
+               container_of(rhp, struct ftrace_func_probe, rcu);
 
        if (entry->ops->free)
                entry->ops->free(&entry->data);
@@ -1436,21 +1465,21 @@ static void ftrace_free_entry_rcu(struct rcu_head *rhp)
 
 
 int
-register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
+register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                              void *data)
 {
-       struct ftrace_func_hook *entry;
+       struct ftrace_func_probe *entry;
        struct ftrace_page *pg;
        struct dyn_ftrace *rec;
-       unsigned long key;
        int type, len, not;
+       unsigned long key;
        int count = 0;
        char *search;
 
        type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
        len = strlen(search);
 
-       /* we do not support '!' for function hooks */
+       /* we do not support '!' for function probes */
        if (WARN_ON(not))
                return -EINVAL;
 
@@ -1465,7 +1494,7 @@ register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
 
                entry = kmalloc(sizeof(*entry), GFP_KERNEL);
                if (!entry) {
-                       /* If we did not hook to any, then return error */
+                       /* If we did not process any, then return error */
                        if (!count)
                                count = -ENOMEM;
                        goto out_unlock;
@@ -1495,7 +1524,7 @@ register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
                hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]);
 
        } while_for_each_ftrace_rec();
-       __enable_ftrace_function_hook();
+       __enable_ftrace_function_probe();
 
  out_unlock:
        mutex_unlock(&ftrace_lock);
@@ -1504,15 +1533,15 @@ register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
 }
 
 enum {
-       HOOK_TEST_FUNC          = 1,
-       HOOK_TEST_DATA          = 2
+       PROBE_TEST_FUNC         = 1,
+       PROBE_TEST_DATA         = 2
 };
 
 static void
-__unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
+__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                                  void *data, int flags)
 {
-       struct ftrace_func_hook *entry;
+       struct ftrace_func_probe *entry;
        struct hlist_node *n, *tmp;
        char str[KSYM_SYMBOL_LEN];
        int type = MATCH_FULL;
@@ -1527,7 +1556,7 @@ __unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
                type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
                len = strlen(search);
 
-               /* we do not support '!' for function hooks */
+               /* we do not support '!' for function probes */
                if (WARN_ON(not))
                        return;
        }
@@ -1539,10 +1568,10 @@ __unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
                hlist_for_each_entry_safe(entry, n, tmp, hhd, node) {
 
                        /* break up if statements for readability */
-                       if ((flags & HOOK_TEST_FUNC) && entry->ops != ops)
+                       if ((flags & PROBE_TEST_FUNC) && entry->ops != ops)
                                continue;
 
-                       if ((flags & HOOK_TEST_DATA) && entry->data != data)
+                       if ((flags & PROBE_TEST_DATA) && entry->data != data)
                                continue;
 
                        /* do this last, since it is the most expensive */
@@ -1557,27 +1586,27 @@ __unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
                        call_rcu(&entry->rcu, ftrace_free_entry_rcu);
                }
        }
-       __disable_ftrace_function_hook();
+       __disable_ftrace_function_probe();
        mutex_unlock(&ftrace_lock);
 }
 
 void
-unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
+unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                                void *data)
 {
-       __unregister_ftrace_function_hook(glob, ops, data,
-                                         HOOK_TEST_FUNC | HOOK_TEST_DATA);
+       __unregister_ftrace_function_probe(glob, ops, data,
+                                         PROBE_TEST_FUNC | PROBE_TEST_DATA);
 }
 
 void
-unregister_ftrace_function_hook_func(char *glob, struct ftrace_hook_ops *ops)
+unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
 {
-       __unregister_ftrace_function_hook(glob, ops, NULL, HOOK_TEST_FUNC);
+       __unregister_ftrace_function_probe(glob, ops, NULL, PROBE_TEST_FUNC);
 }
 
-void unregister_ftrace_function_hook_all(char *glob)
+void unregister_ftrace_function_probe_all(char *glob)
 {
-       __unregister_ftrace_function_hook(glob, NULL, NULL, 0);
+       __unregister_ftrace_function_probe(glob, NULL, NULL, 0);
 }
 
 static LIST_HEAD(ftrace_commands);
@@ -1623,8 +1652,8 @@ int unregister_ftrace_command(struct ftrace_func_command *cmd)
 
 static int ftrace_process_regex(char *buff, int len, int enable)
 {
-       struct ftrace_func_command *p;
        char *func, *command, *next = buff;
+       struct ftrace_func_command *p;
        int ret = -EINVAL;
 
        func = strsep(&next, ":");
@@ -1835,21 +1864,21 @@ ftrace_notrace_release(struct inode *inode, struct file *file)
        return ftrace_regex_release(inode, file, 0);
 }
 
-static struct file_operations ftrace_avail_fops = {
+static const struct file_operations ftrace_avail_fops = {
        .open = ftrace_avail_open,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = ftrace_avail_release,
 };
 
-static struct file_operations ftrace_failures_fops = {
+static const struct file_operations ftrace_failures_fops = {
        .open = ftrace_failures_open,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = ftrace_avail_release,
 };
 
-static struct file_operations ftrace_filter_fops = {
+static const struct file_operations ftrace_filter_fops = {
        .open = ftrace_filter_open,
        .read = ftrace_regex_read,
        .write = ftrace_filter_write,
@@ -1857,7 +1886,7 @@ static struct file_operations ftrace_filter_fops = {
        .release = ftrace_filter_release,
 };
 
-static struct file_operations ftrace_notrace_fops = {
+static const struct file_operations ftrace_notrace_fops = {
        .open = ftrace_notrace_open,
        .read = ftrace_regex_read,
        .write = ftrace_notrace_write,
@@ -1892,6 +1921,10 @@ static void *g_start(struct seq_file *m, loff_t *pos)
 
        mutex_lock(&graph_lock);
 
+       /* Nothing, tell g_show to print all functions are enabled */
+       if (!ftrace_graph_count && !*pos)
+               return (void *)1;
+
        p = g_next(m, p, pos);
 
        return p;
@@ -1910,6 +1943,11 @@ static int g_show(struct seq_file *m, void *v)
        if (!ptr)
                return 0;
 
+       if (ptr == (unsigned long *)1) {
+               seq_printf(m, "#### all functions enabled ####\n");
+               return 0;
+       }
+
        kallsyms_lookup(*ptr, NULL, NULL, NULL, str);
 
        seq_printf(m, "%s\n", str);
@@ -1963,38 +2001,51 @@ ftrace_graph_read(struct file *file, char __user *ubuf,
 }
 
 static int
-ftrace_set_func(unsigned long *array, int idx, char *buffer)
+ftrace_set_func(unsigned long *array, int *idx, char *buffer)
 {
-       char str[KSYM_SYMBOL_LEN];
        struct dyn_ftrace *rec;
        struct ftrace_page *pg;
+       int search_len;
        int found = 0;
-       int j;
+       int type, not;
+       char *search;
+       bool exists;
+       int i;
 
        if (ftrace_disabled)
                return -ENODEV;
 
+       /* decode regex */
+       type = ftrace_setup_glob(buffer, strlen(buffer), &search, &not);
+       if (not)
+               return -EINVAL;
+
+       search_len = strlen(search);
+
        mutex_lock(&ftrace_lock);
        do_for_each_ftrace_rec(pg, rec) {
 
+               if (*idx >= FTRACE_GRAPH_MAX_FUNCS)
+                       break;
+
                if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE))
                        continue;
 
-               kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
-               if (strcmp(str, buffer) == 0) {
-                       /* Return 1 if we add it to the array */
-                       found = 1;
-                       for (j = 0; j < idx; j++)
-                               if (array[j] == rec->ip) {
-                                       found = 0;
+               if (ftrace_match_record(rec, search, search_len, type)) {
+                       /* ensure it is not already in the array */
+                       exists = false;
+                       for (i = 0; i < *idx; i++)
+                               if (array[i] == rec->ip) {
+                                       exists = true;
                                        break;
                                }
-                       if (found)
-                               array[idx] = rec->ip;
-                       goto out;
+                       if (!exists) {
+                               array[(*idx)++] = rec->ip;
+                               found = 1;
+                       }
                }
        } while_for_each_ftrace_rec();
- out:
+
        mutex_unlock(&ftrace_lock);
 
        return found ? 0 : -EINVAL;
@@ -2063,13 +2114,11 @@ ftrace_graph_write(struct file *file, const char __user *ubuf,
        }
        buffer[index] = 0;
 
-       /* we allow only one at a time */
-       ret = ftrace_set_func(array, ftrace_graph_count, buffer);
+       /* we allow only one expression at a time */
+       ret = ftrace_set_func(array, &ftrace_graph_count, buffer);
        if (ret)
                goto out;
 
-       ftrace_graph_count++;
-
        file->f_pos += read;
 
        ret = read;
@@ -2369,7 +2418,7 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf,
        return cnt;
 }
 
-static struct file_operations ftrace_pid_fops = {
+static const struct file_operations ftrace_pid_fops = {
        .read = ftrace_pid_read,
        .write = ftrace_pid_write,
 };
@@ -2392,7 +2441,6 @@ static __init int ftrace_init_debugfs(void)
                           "'set_ftrace_pid' entry\n");
        return 0;
 }
-
 fs_initcall(ftrace_init_debugfs);
 
 /**