summaryrefslogtreecommitdiff
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.c20
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/sort.c17
-rw-r--r--tools/perf/util/srcline.c83
-rw-r--r--tools/perf/util/util.h5
5 files changed, 95 insertions, 32 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index c6fd1870f278..d48297d77e19 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1070,7 +1070,7 @@ static void symbol__free_source_line(struct symbol *sym, int len)
(sizeof(src_line->p) * (src_line->nr_pcnt - 1));
for (i = 0; i < len; i++) {
- free(src_line->path);
+ free_srcline(src_line->path);
src_line = (void *)src_line + sizeof_src_line;
}
@@ -1087,7 +1087,6 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
u64 start;
int i, k;
int evidx = evsel->idx;
- char cmd[PATH_MAX * 2];
struct source_line *src_line;
struct annotation *notes = symbol__annotation(sym);
struct sym_hist *h = annotation__histogram(notes, evidx);
@@ -1115,10 +1114,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
start = map__rip_2objdump(map, sym->start);
for (i = 0; i < len; i++) {
- char *path = NULL;
- size_t line_len;
u64 offset;
- FILE *fp;
double percent_max = 0.0;
src_line->nr_pcnt = nr_pcnt;
@@ -1135,19 +1131,9 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
goto next;
offset = start + i;
- sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
- fp = popen(cmd, "r");
- if (!fp)
- goto next;
-
- if (getline(&path, &line_len, fp) < 0 || !line_len)
- goto next_close;
-
- src_line->path = path;
+ src_line->path = get_srcline(filename, offset);
insert_source_line(&tmp_root, src_line);
- next_close:
- pclose(fp);
next:
src_line = (void *)src_line + sizeof_src_line;
}
@@ -1188,7 +1174,7 @@ static void print_summary(struct rb_root *root, const char *filename)
path = src_line->path;
color = get_percent_color(percent_max);
- color_fprintf(stdout, color, " %s", path);
+ color_fprintf(stdout, color, " %s\n", path);
node = rb_next(node);
}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e6fc38a86e2c..cca03831f41a 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -535,7 +535,7 @@ void hist_entry__free(struct hist_entry *he)
{
free(he->branch_info);
free(he->mem_info);
- free(he->srcline);
+ free_srcline(he->srcline);
free(he);
}
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 97cf3ef4417c..b7e0ef0445de 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -251,8 +251,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
unsigned int width __maybe_unused)
{
FILE *fp = NULL;
- char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
- size_t line_len;
+ char *path = self->srcline;
if (path != NULL)
goto out_path;
@@ -263,19 +262,9 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
goto out_ip;
- snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
- self->ms.map->dso->long_name, self->ip);
- fp = popen(cmd, "r");
- if (!fp)
- goto out_ip;
-
- if (getline(&self->srcline, &line_len, fp) < 0 || !line_len)
- goto out_ip;
+ path = get_srcline(self->ms.map->dso->long_name, self->ip);
+ self->srcline = path;
- nl = strchr(self->srcline, '\n');
- if (nl != NULL)
- *nl = '\0';
- path = self->srcline;
out_path:
if (fp)
pclose(fp);
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
new file mode 100644
index 000000000000..7e92cca6f502
--- /dev/null
+++ b/tools/perf/util/srcline.c
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/kernel.h>
+
+#include "util/util.h"
+#include "util/debug.h"
+
+static int addr2line(const char *dso_name, unsigned long addr,
+ char **file, unsigned int *line_nr)
+{
+ FILE *fp;
+ char cmd[PATH_MAX];
+ char *filename = NULL;
+ size_t len;
+ char *sep;
+ int ret = 0;
+
+ scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
+ dso_name, addr);
+
+ fp = popen(cmd, "r");
+ if (fp == NULL) {
+ pr_warning("popen failed for %s\n", dso_name);
+ return 0;
+ }
+
+ if (getline(&filename, &len, fp) < 0 || !len) {
+ pr_warning("addr2line has no output for %s\n", dso_name);
+ goto out;
+ }
+
+ sep = strchr(filename, '\n');
+ if (sep)
+ *sep = '\0';
+
+ if (!strcmp(filename, "??:0")) {
+ pr_debug("no debugging info in %s\n", dso_name);
+ free(filename);
+ goto out;
+ }
+
+ sep = strchr(filename, ':');
+ if (sep) {
+ *sep++ = '\0';
+ *file = filename;
+ *line_nr = strtoul(sep, NULL, 0);
+ ret = 1;
+ }
+out:
+ pclose(fp);
+ return ret;
+}
+
+char *get_srcline(const char *dso_name, unsigned long addr)
+{
+ char *file;
+ unsigned line;
+ char *srcline;
+ size_t size;
+
+ if (!addr2line(dso_name, addr, &file, &line))
+ return SRCLINE_UNKNOWN;
+
+ /* just calculate actual length */
+ size = snprintf(NULL, 0, "%s:%u", file, line) + 1;
+
+ srcline = malloc(size);
+ if (srcline)
+ snprintf(srcline, size, "%s:%u", file, line);
+ else
+ srcline = SRCLINE_UNKNOWN;
+
+ free(file);
+ return srcline;
+}
+
+void free_srcline(char *srcline)
+{
+ if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
+ free(srcline);
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 7fd840bf6b62..7c8b43fa8898 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -297,4 +297,9 @@ struct parse_tag {
};
unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
+
+#define SRCLINE_UNKNOWN ((char *) "??:0")
+
+char *get_srcline(const char *dso_name, unsigned long addr);
+void free_srcline(char *srcline);
#endif /* GIT_COMPAT_UTIL_H */