xref: /openbmc/linux/tools/perf/util/srcline.c (revision 58d91a0068694a5ba3efc99e88ce6b4b0dd0d085)
1f048d548SNamhyung Kim #include <stdio.h>
2f048d548SNamhyung Kim #include <stdlib.h>
3f048d548SNamhyung Kim #include <string.h>
4f048d548SNamhyung Kim 
5f048d548SNamhyung Kim #include <linux/kernel.h>
6f048d548SNamhyung Kim 
7f048d548SNamhyung Kim #include "util/util.h"
8f048d548SNamhyung Kim #include "util/debug.h"
9f048d548SNamhyung Kim 
10f048d548SNamhyung Kim static int addr2line(const char *dso_name, unsigned long addr,
11f048d548SNamhyung Kim 		     char **file, unsigned int *line_nr)
12f048d548SNamhyung Kim {
13f048d548SNamhyung Kim 	FILE *fp;
14f048d548SNamhyung Kim 	char cmd[PATH_MAX];
15f048d548SNamhyung Kim 	char *filename = NULL;
16f048d548SNamhyung Kim 	size_t len;
17f048d548SNamhyung Kim 	char *sep;
18f048d548SNamhyung Kim 	int ret = 0;
19f048d548SNamhyung Kim 
20f048d548SNamhyung Kim 	scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
21f048d548SNamhyung Kim 		  dso_name, addr);
22f048d548SNamhyung Kim 
23f048d548SNamhyung Kim 	fp = popen(cmd, "r");
24f048d548SNamhyung Kim 	if (fp == NULL) {
25f048d548SNamhyung Kim 		pr_warning("popen failed for %s\n", dso_name);
26f048d548SNamhyung Kim 		return 0;
27f048d548SNamhyung Kim 	}
28f048d548SNamhyung Kim 
29f048d548SNamhyung Kim 	if (getline(&filename, &len, fp) < 0 || !len) {
30f048d548SNamhyung Kim 		pr_warning("addr2line has no output for %s\n", dso_name);
31f048d548SNamhyung Kim 		goto out;
32f048d548SNamhyung Kim 	}
33f048d548SNamhyung Kim 
34f048d548SNamhyung Kim 	sep = strchr(filename, '\n');
35f048d548SNamhyung Kim 	if (sep)
36f048d548SNamhyung Kim 		*sep = '\0';
37f048d548SNamhyung Kim 
38f048d548SNamhyung Kim 	if (!strcmp(filename, "??:0")) {
39f048d548SNamhyung Kim 		pr_debug("no debugging info in %s\n", dso_name);
40f048d548SNamhyung Kim 		free(filename);
41f048d548SNamhyung Kim 		goto out;
42f048d548SNamhyung Kim 	}
43f048d548SNamhyung Kim 
44f048d548SNamhyung Kim 	sep = strchr(filename, ':');
45f048d548SNamhyung Kim 	if (sep) {
46f048d548SNamhyung Kim 		*sep++ = '\0';
47f048d548SNamhyung Kim 		*file = filename;
48f048d548SNamhyung Kim 		*line_nr = strtoul(sep, NULL, 0);
49f048d548SNamhyung Kim 		ret = 1;
50f048d548SNamhyung Kim 	}
51f048d548SNamhyung Kim out:
52f048d548SNamhyung Kim 	pclose(fp);
53f048d548SNamhyung Kim 	return ret;
54f048d548SNamhyung Kim }
55f048d548SNamhyung Kim 
56f048d548SNamhyung Kim char *get_srcline(const char *dso_name, unsigned long addr)
57f048d548SNamhyung Kim {
58f048d548SNamhyung Kim 	char *file;
59f048d548SNamhyung Kim 	unsigned line;
60*58d91a00SNamhyung Kim 	char *srcline = SRCLINE_UNKNOWN;
61f048d548SNamhyung Kim 	size_t size;
62f048d548SNamhyung Kim 
63*58d91a00SNamhyung Kim 	if (dso_name[0] == '[')
64*58d91a00SNamhyung Kim 		goto out;
65*58d91a00SNamhyung Kim 
66*58d91a00SNamhyung Kim 	if (!strncmp(dso_name, "/tmp/perf-", 10))
67*58d91a00SNamhyung Kim 		goto out;
68*58d91a00SNamhyung Kim 
69f048d548SNamhyung Kim 	if (!addr2line(dso_name, addr, &file, &line))
70*58d91a00SNamhyung Kim 		goto out;
71f048d548SNamhyung Kim 
72f048d548SNamhyung Kim 	/* just calculate actual length */
73f048d548SNamhyung Kim 	size = snprintf(NULL, 0, "%s:%u", file, line) + 1;
74f048d548SNamhyung Kim 
75f048d548SNamhyung Kim 	srcline = malloc(size);
76f048d548SNamhyung Kim 	if (srcline)
77f048d548SNamhyung Kim 		snprintf(srcline, size, "%s:%u", file, line);
78f048d548SNamhyung Kim 	else
79f048d548SNamhyung Kim 		srcline = SRCLINE_UNKNOWN;
80f048d548SNamhyung Kim 
81f048d548SNamhyung Kim 	free(file);
82*58d91a00SNamhyung Kim out:
83f048d548SNamhyung Kim 	return srcline;
84f048d548SNamhyung Kim }
85f048d548SNamhyung Kim 
86f048d548SNamhyung Kim void free_srcline(char *srcline)
87f048d548SNamhyung Kim {
88f048d548SNamhyung Kim 	if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
89f048d548SNamhyung Kim 		free(srcline);
90f048d548SNamhyung Kim }
91