]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/perf/util/probe-finder.c
perf probe: Fix wrong address verification
[linux.git] / tools / perf / util / probe-finder.c
index 505905fc21c54440e3fab59966ec09d59026ef7d..2b6513e5725c56af83662f3b0586032ebc63d403 100644 (file)
@@ -604,38 +604,26 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
                                  const char *function,
                                  struct probe_trace_point *tp)
 {
-       Dwarf_Addr eaddr, highaddr;
+       Dwarf_Addr eaddr;
        GElf_Sym sym;
        const char *symbol;
 
        /* Verify the address is correct */
-       if (dwarf_entrypc(sp_die, &eaddr) != 0) {
-               pr_warning("Failed to get entry address of %s\n",
-                          dwarf_diename(sp_die));
-               return -ENOENT;
-       }
-       if (dwarf_highpc(sp_die, &highaddr) != 0) {
-               pr_warning("Failed to get end address of %s\n",
-                          dwarf_diename(sp_die));
-               return -ENOENT;
-       }
-       if (paddr > highaddr) {
-               pr_warning("Offset specified is greater than size of %s\n",
+       if (!dwarf_haspc(sp_die, paddr)) {
+               pr_warning("Specified offset is out of %s\n",
                           dwarf_diename(sp_die));
                return -EINVAL;
        }
 
-       symbol = dwarf_diename(sp_die);
+       /* Try to get actual symbol name from symtab */
+       symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
        if (!symbol) {
-               /* Try to get the symbol name from symtab */
-               symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
-               if (!symbol) {
-                       pr_warning("Failed to find symbol at 0x%lx\n",
-                                  (unsigned long)paddr);
-                       return -ENOENT;
-               }
-               eaddr = sym.st_value;
+               pr_warning("Failed to find symbol at 0x%lx\n",
+                          (unsigned long)paddr);
+               return -ENOENT;
        }
+       eaddr = sym.st_value;
+
        tp->offset = (unsigned long)(paddr - eaddr);
        tp->address = (unsigned long)paddr;
        tp->symbol = strdup(symbol);
@@ -1245,6 +1233,17 @@ static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
        return n;
 }
 
+static bool trace_event_finder_overlap(struct trace_event_finder *tf)
+{
+       int i;
+
+       for (i = 0; i < tf->ntevs; i++) {
+               if (tf->pf.addr == tf->tevs[i].point.address)
+                       return true;
+       }
+       return false;
+}
+
 /* Add a found probe point into trace event list */
 static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
@@ -1255,6 +1254,14 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
        struct perf_probe_arg *args = NULL;
        int ret, i;
 
+       /*
+        * For some reason (e.g. different column assigned to same address)
+        * This callback can be called with the address which already passed.
+        * Ignore it first.
+        */
+       if (trace_event_finder_overlap(tf))
+               return 0;
+
        /* Check number of tevs */
        if (tf->ntevs == tf->max_tevs) {
                pr_warning("Too many( > %d) probe point found.\n",