tracing/kprobes: Return EADDRNOTAVAIL when func matches several symbols
[linux-2.6-microblaze.git] / kernel / trace / trace_kprobe.c
index 3d7a180..a8fef6a 100644 (file)
@@ -705,6 +705,25 @@ static struct notifier_block trace_kprobe_module_nb = {
        .priority = 1   /* Invoked after kprobe module callback */
 };
 
+static int count_symbols(void *data, unsigned long unused)
+{
+       unsigned int *count = data;
+
+       (*count)++;
+
+       return 0;
+}
+
+static unsigned int number_of_same_symbols(char *func_name)
+{
+       unsigned int count;
+
+       count = 0;
+       kallsyms_on_each_match_symbol(count_symbols, func_name, &count);
+
+       return count;
+}
+
 static int __trace_kprobe_create(int argc, const char *argv[])
 {
        /*
@@ -836,6 +855,31 @@ static int __trace_kprobe_create(int argc, const char *argv[])
                }
        }
 
+       if (symbol && !strchr(symbol, ':')) {
+               unsigned int count;
+
+               count = number_of_same_symbols(symbol);
+               if (count > 1) {
+                       /*
+                        * Users should use ADDR to remove the ambiguity of
+                        * using KSYM only.
+                        */
+                       trace_probe_log_err(0, NON_UNIQ_SYMBOL);
+                       ret = -EADDRNOTAVAIL;
+
+                       goto error;
+               } else if (count == 0) {
+                       /*
+                        * We can return ENOENT earlier than when register the
+                        * kprobe.
+                        */
+                       trace_probe_log_err(0, BAD_PROBE_ADDR);
+                       ret = -ENOENT;
+
+                       goto error;
+               }
+       }
+
        trace_probe_log_set_index(0);
        if (event) {
                ret = traceprobe_parse_event_name(&event, &group, gbuf,
@@ -1695,6 +1739,7 @@ static int unregister_kprobe_event(struct trace_kprobe *tk)
 }
 
 #ifdef CONFIG_PERF_EVENTS
+
 /* create a trace_kprobe, but don't add it to global lists */
 struct trace_event_call *
 create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
@@ -1705,6 +1750,24 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
        int ret;
        char *event;
 
+       if (func) {
+               unsigned int count;
+
+               count = number_of_same_symbols(func);
+               if (count > 1)
+                       /*
+                        * Users should use addr to remove the ambiguity of
+                        * using func only.
+                        */
+                       return ERR_PTR(-EADDRNOTAVAIL);
+               else if (count == 0)
+                       /*
+                        * We can return ENOENT earlier than when register the
+                        * kprobe.
+                        */
+                       return ERR_PTR(-ENOENT);
+       }
+
        /*
         * local trace_kprobes are not added to dyn_event, so they are never
         * searched in find_trace_kprobe(). Therefore, there is no concern of