]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/perf/util/probe-event.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / tools / perf / util / probe-event.c
index 4a57c8a60bd91990fad493b9a16e265831cb88a5..35f5b7b7715c39e054591644d88b369bbf35de5e 100644 (file)
@@ -610,6 +610,33 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
        return ret ? : -ENOENT;
 }
 
+/* Adjust symbol name and address */
+static int post_process_probe_trace_point(struct probe_trace_point *tp,
+                                          struct map *map, unsigned long offs)
+{
+       struct symbol *sym;
+       u64 addr = tp->address + tp->offset - offs;
+
+       sym = map__find_symbol(map, addr);
+       if (!sym)
+               return -ENOENT;
+
+       if (strcmp(sym->name, tp->symbol)) {
+               /* If we have no realname, use symbol for it */
+               if (!tp->realname)
+                       tp->realname = tp->symbol;
+               else
+                       free(tp->symbol);
+               tp->symbol = strdup(sym->name);
+               if (!tp->symbol)
+                       return -ENOMEM;
+       }
+       tp->offset = addr - sym->start;
+       tp->address -= offs;
+
+       return 0;
+}
+
 /*
  * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
  * and generate new symbols with suffixes such as .constprop.N or .isra.N
@@ -622,11 +649,9 @@ static int
 post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
                                        int ntevs, const char *pathname)
 {
-       struct symbol *sym;
        struct map *map;
        unsigned long stext = 0;
-       u64 addr;
-       int i;
+       int i, ret = 0;
 
        /* Prepare a map for offline binary */
        map = dso__new_map(pathname);
@@ -636,23 +661,14 @@ post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
        }
 
        for (i = 0; i < ntevs; i++) {
-               addr = tevs[i].point.address + tevs[i].point.offset - stext;
-               sym = map__find_symbol(map, addr);
-               if (!sym)
-                       continue;
-               if (!strcmp(sym->name, tevs[i].point.symbol))
-                       continue;
-               /* If we have no realname, use symbol for it */
-               if (!tevs[i].point.realname)
-                       tevs[i].point.realname = tevs[i].point.symbol;
-               else
-                       free(tevs[i].point.symbol);
-               tevs[i].point.symbol = strdup(sym->name);
-               tevs[i].point.offset = addr - sym->start;
+               ret = post_process_probe_trace_point(&tevs[i].point,
+                                                    map, stext);
+               if (ret < 0)
+                       break;
        }
        map__put(map);
 
-       return 0;
+       return ret;
 }
 
 static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
@@ -682,18 +698,31 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
        return ret;
 }
 
-static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
-                                           int ntevs, const char *module)
+static int
+post_process_module_probe_trace_events(struct probe_trace_event *tevs,
+                                      int ntevs, const char *module,
+                                      struct debuginfo *dinfo)
 {
+       Dwarf_Addr text_offs = 0;
        int i, ret = 0;
        char *mod_name = NULL;
+       struct map *map;
 
        if (!module)
                return 0;
 
-       mod_name = find_module_name(module);
+       map = get_target_map(module, false);
+       if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) {
+               pr_warning("Failed to get ELF symbols for %s\n", module);
+               return -EINVAL;
+       }
 
+       mod_name = find_module_name(module);
        for (i = 0; i < ntevs; i++) {
+               ret = post_process_probe_trace_point(&tevs[i].point,
+                                               map, (unsigned long)text_offs);
+               if (ret < 0)
+                       break;
                tevs[i].point.module =
                        strdup(mod_name ? mod_name : module);
                if (!tevs[i].point.module) {
@@ -703,6 +732,8 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
        }
 
        free(mod_name);
+       map__put(map);
+
        return ret;
 }
 
@@ -760,7 +791,7 @@ arch__post_process_probe_trace_events(struct perf_probe_event *pev __maybe_unuse
 static int post_process_probe_trace_events(struct perf_probe_event *pev,
                                           struct probe_trace_event *tevs,
                                           int ntevs, const char *module,
-                                          bool uprobe)
+                                          bool uprobe, struct debuginfo *dinfo)
 {
        int ret;
 
@@ -768,7 +799,8 @@ static int post_process_probe_trace_events(struct perf_probe_event *pev,
                ret = add_exec_to_probe_trace_events(tevs, ntevs, module);
        else if (module)
                /* Currently ref_reloc_sym based probe is not for drivers */
-               ret = add_module_to_probe_trace_events(tevs, ntevs, module);
+               ret = post_process_module_probe_trace_events(tevs, ntevs,
+                                                            module, dinfo);
        else
                ret = post_process_kernel_probe_trace_events(tevs, ntevs);
 
@@ -812,30 +844,27 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
                }
        }
 
-       debuginfo__delete(dinfo);
-
        if (ntevs > 0) {        /* Succeeded to find trace events */
                pr_debug("Found %d probe_trace_events.\n", ntevs);
                ret = post_process_probe_trace_events(pev, *tevs, ntevs,
-                                               pev->target, pev->uprobes);
+                                       pev->target, pev->uprobes, dinfo);
                if (ret < 0 || ret == ntevs) {
+                       pr_debug("Post processing failed or all events are skipped. (%d)\n", ret);
                        clear_probe_trace_events(*tevs, ntevs);
                        zfree(tevs);
+                       ntevs = 0;
                }
-               if (ret != ntevs)
-                       return ret < 0 ? ret : ntevs;
-               ntevs = 0;
-               /* Fall through */
        }
 
+       debuginfo__delete(dinfo);
+
        if (ntevs == 0) {       /* No error but failed to find probe point. */
                pr_warning("Probe point '%s' not found.\n",
                           synthesize_perf_probe_point(&pev->point));
                return -ENOENT;
-       }
-       /* Error path : ntevs < 0 */
-       pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
-       if (ntevs < 0) {
+       } else if (ntevs < 0) {
+               /* Error path : ntevs < 0 */
+               pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
                if (ntevs == -EBADF)
                        pr_warning("Warning: No dwarf info found in the vmlinux - "
                                "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
@@ -2032,7 +2061,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
                                          bool is_kprobe)
 {
        struct symbol *sym = NULL;
-       struct map *map;
+       struct map *map = NULL;
        u64 addr = tp->address;
        int ret = -ENOENT;
 
@@ -2994,20 +3023,17 @@ static int try_to_find_absolute_address(struct perf_probe_event *pev,
 
        tev->nargs = pev->nargs;
        tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
-       if (!tev->args) {
-               err = -ENOMEM;
+       if (!tev->args)
                goto errout;
-       }
+
        for (i = 0; i < tev->nargs; i++)
                copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]);
 
        return 1;
 
 errout:
-       if (*tevs) {
-               clear_probe_trace_events(*tevs, 1);
-               *tevs = NULL;
-       }
+       clear_probe_trace_events(*tevs, 1);
+       *tevs = NULL;
        return err;
 }