xref: /openbmc/linux/tools/perf/util/srcline.c (revision 981ab3f1)
1 #include <inttypes.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <linux/kernel.h>
7 
8 #include "util/dso.h"
9 #include "util/util.h"
10 #include "util/debug.h"
11 #include "util/callchain.h"
12 #include "srcline.h"
13 
14 #include "symbol.h"
15 
16 bool srcline_full_filename;
17 
18 static const char *dso__name(struct dso *dso)
19 {
20 	const char *dso_name;
21 
22 	if (dso->symsrc_filename)
23 		dso_name = dso->symsrc_filename;
24 	else
25 		dso_name = dso->long_name;
26 
27 	if (dso_name[0] == '[')
28 		return NULL;
29 
30 	if (!strncmp(dso_name, "/tmp/perf-", 10))
31 		return NULL;
32 
33 	return dso_name;
34 }
35 
36 static int inline_list__append(char *filename, char *funcname, int line_nr,
37 			       struct inline_node *node, struct dso *dso)
38 {
39 	struct inline_list *ilist;
40 	char *demangled;
41 
42 	ilist = zalloc(sizeof(*ilist));
43 	if (ilist == NULL)
44 		return -1;
45 
46 	ilist->filename = filename;
47 	ilist->line_nr = line_nr;
48 
49 	if (dso != NULL) {
50 		demangled = dso__demangle_sym(dso, 0, funcname);
51 		if (demangled == NULL) {
52 			ilist->funcname = funcname;
53 		} else {
54 			ilist->funcname = demangled;
55 			free(funcname);
56 		}
57 	}
58 
59 	if (callchain_param.order == ORDER_CALLEE)
60 		list_add_tail(&ilist->list, &node->val);
61 	else
62 		list_add(&ilist->list, &node->val);
63 
64 	return 0;
65 }
66 
67 #ifdef HAVE_LIBBFD_SUPPORT
68 
69 /*
70  * Implement addr2line using libbfd.
71  */
72 #define PACKAGE "perf"
73 #include <bfd.h>
74 
75 struct a2l_data {
76 	const char 	*input;
77 	u64	 	addr;
78 
79 	bool 		found;
80 	const char 	*filename;
81 	const char 	*funcname;
82 	unsigned 	line;
83 
84 	bfd 		*abfd;
85 	asymbol 	**syms;
86 };
87 
88 static int bfd_error(const char *string)
89 {
90 	const char *errmsg;
91 
92 	errmsg = bfd_errmsg(bfd_get_error());
93 	fflush(stdout);
94 
95 	if (string)
96 		pr_debug("%s: %s\n", string, errmsg);
97 	else
98 		pr_debug("%s\n", errmsg);
99 
100 	return -1;
101 }
102 
103 static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
104 {
105 	long storage;
106 	long symcount;
107 	asymbol **syms;
108 	bfd_boolean dynamic = FALSE;
109 
110 	if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
111 		return bfd_error(bfd_get_filename(abfd));
112 
113 	storage = bfd_get_symtab_upper_bound(abfd);
114 	if (storage == 0L) {
115 		storage = bfd_get_dynamic_symtab_upper_bound(abfd);
116 		dynamic = TRUE;
117 	}
118 	if (storage < 0L)
119 		return bfd_error(bfd_get_filename(abfd));
120 
121 	syms = malloc(storage);
122 	if (dynamic)
123 		symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
124 	else
125 		symcount = bfd_canonicalize_symtab(abfd, syms);
126 
127 	if (symcount < 0) {
128 		free(syms);
129 		return bfd_error(bfd_get_filename(abfd));
130 	}
131 
132 	a2l->syms = syms;
133 	return 0;
134 }
135 
136 static void find_address_in_section(bfd *abfd, asection *section, void *data)
137 {
138 	bfd_vma pc, vma;
139 	bfd_size_type size;
140 	struct a2l_data *a2l = data;
141 
142 	if (a2l->found)
143 		return;
144 
145 	if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
146 		return;
147 
148 	pc = a2l->addr;
149 	vma = bfd_get_section_vma(abfd, section);
150 	size = bfd_get_section_size(section);
151 
152 	if (pc < vma || pc >= vma + size)
153 		return;
154 
155 	a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
156 					   &a2l->filename, &a2l->funcname,
157 					   &a2l->line);
158 }
159 
160 static struct a2l_data *addr2line_init(const char *path)
161 {
162 	bfd *abfd;
163 	struct a2l_data *a2l = NULL;
164 
165 	abfd = bfd_openr(path, NULL);
166 	if (abfd == NULL)
167 		return NULL;
168 
169 	if (!bfd_check_format(abfd, bfd_object))
170 		goto out;
171 
172 	a2l = zalloc(sizeof(*a2l));
173 	if (a2l == NULL)
174 		goto out;
175 
176 	a2l->abfd = abfd;
177 	a2l->input = strdup(path);
178 	if (a2l->input == NULL)
179 		goto out;
180 
181 	if (slurp_symtab(abfd, a2l))
182 		goto out;
183 
184 	return a2l;
185 
186 out:
187 	if (a2l) {
188 		zfree((char **)&a2l->input);
189 		free(a2l);
190 	}
191 	bfd_close(abfd);
192 	return NULL;
193 }
194 
195 static void addr2line_cleanup(struct a2l_data *a2l)
196 {
197 	if (a2l->abfd)
198 		bfd_close(a2l->abfd);
199 	zfree((char **)&a2l->input);
200 	zfree(&a2l->syms);
201 	free(a2l);
202 }
203 
204 #define MAX_INLINE_NEST 1024
205 
206 static int inline_list__append_dso_a2l(struct dso *dso,
207 				       struct inline_node *node)
208 {
209 	struct a2l_data *a2l = dso->a2l;
210 	char *funcname = a2l->funcname ? strdup(a2l->funcname) : NULL;
211 	char *filename = a2l->filename ? strdup(a2l->filename) : NULL;
212 
213 	return inline_list__append(filename, funcname, a2l->line, node, dso);
214 }
215 
216 static int addr2line(const char *dso_name, u64 addr,
217 		     char **file, unsigned int *line, struct dso *dso,
218 		     bool unwind_inlines, struct inline_node *node)
219 {
220 	int ret = 0;
221 	struct a2l_data *a2l = dso->a2l;
222 
223 	if (!a2l) {
224 		dso->a2l = addr2line_init(dso_name);
225 		a2l = dso->a2l;
226 	}
227 
228 	if (a2l == NULL) {
229 		pr_warning("addr2line_init failed for %s\n", dso_name);
230 		return 0;
231 	}
232 
233 	a2l->addr = addr;
234 	a2l->found = false;
235 
236 	bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
237 
238 	if (!a2l->found)
239 		return 0;
240 
241 	if (unwind_inlines) {
242 		int cnt = 0;
243 
244 		if (node && inline_list__append_dso_a2l(dso, node))
245 			return 0;
246 
247 		while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
248 					     &a2l->funcname, &a2l->line) &&
249 		       cnt++ < MAX_INLINE_NEST) {
250 
251 			if (node != NULL) {
252 				if (inline_list__append_dso_a2l(dso, node))
253 					return 0;
254 				// found at least one inline frame
255 				ret = 1;
256 			}
257 		}
258 	}
259 
260 	if (file) {
261 		*file = a2l->filename ? strdup(a2l->filename) : NULL;
262 		ret = *file ? 1 : 0;
263 	}
264 
265 	if (line)
266 		*line = a2l->line;
267 
268 	return ret;
269 }
270 
271 void dso__free_a2l(struct dso *dso)
272 {
273 	struct a2l_data *a2l = dso->a2l;
274 
275 	if (!a2l)
276 		return;
277 
278 	addr2line_cleanup(a2l);
279 
280 	dso->a2l = NULL;
281 }
282 
283 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
284 	struct dso *dso)
285 {
286 	struct inline_node *node;
287 
288 	node = zalloc(sizeof(*node));
289 	if (node == NULL) {
290 		perror("not enough memory for the inline node");
291 		return NULL;
292 	}
293 
294 	INIT_LIST_HEAD(&node->val);
295 	node->addr = addr;
296 
297 	if (!addr2line(dso_name, addr, NULL, NULL, dso, TRUE, node))
298 		goto out_free_inline_node;
299 
300 	if (list_empty(&node->val))
301 		goto out_free_inline_node;
302 
303 	return node;
304 
305 out_free_inline_node:
306 	inline_node__delete(node);
307 	return NULL;
308 }
309 
310 #else /* HAVE_LIBBFD_SUPPORT */
311 
312 static int filename_split(char *filename, unsigned int *line_nr)
313 {
314 	char *sep;
315 
316 	sep = strchr(filename, '\n');
317 	if (sep)
318 		*sep = '\0';
319 
320 	if (!strcmp(filename, "??:0"))
321 		return 0;
322 
323 	sep = strchr(filename, ':');
324 	if (sep) {
325 		*sep++ = '\0';
326 		*line_nr = strtoul(sep, NULL, 0);
327 		return 1;
328 	}
329 
330 	return 0;
331 }
332 
333 static int addr2line(const char *dso_name, u64 addr,
334 		     char **file, unsigned int *line_nr,
335 		     struct dso *dso __maybe_unused,
336 		     bool unwind_inlines __maybe_unused,
337 		     struct inline_node *node __maybe_unused)
338 {
339 	FILE *fp;
340 	char cmd[PATH_MAX];
341 	char *filename = NULL;
342 	size_t len;
343 	int ret = 0;
344 
345 	scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
346 		  dso_name, addr);
347 
348 	fp = popen(cmd, "r");
349 	if (fp == NULL) {
350 		pr_warning("popen failed for %s\n", dso_name);
351 		return 0;
352 	}
353 
354 	if (getline(&filename, &len, fp) < 0 || !len) {
355 		pr_warning("addr2line has no output for %s\n", dso_name);
356 		goto out;
357 	}
358 
359 	ret = filename_split(filename, line_nr);
360 	if (ret != 1) {
361 		free(filename);
362 		goto out;
363 	}
364 
365 	*file = filename;
366 
367 out:
368 	pclose(fp);
369 	return ret;
370 }
371 
372 void dso__free_a2l(struct dso *dso __maybe_unused)
373 {
374 }
375 
376 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
377 	struct dso *dso __maybe_unused)
378 {
379 	FILE *fp;
380 	char cmd[PATH_MAX];
381 	struct inline_node *node;
382 	char *filename = NULL;
383 	size_t len;
384 	unsigned int line_nr = 0;
385 
386 	scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
387 		  dso_name, addr);
388 
389 	fp = popen(cmd, "r");
390 	if (fp == NULL) {
391 		pr_err("popen failed for %s\n", dso_name);
392 		return NULL;
393 	}
394 
395 	node = zalloc(sizeof(*node));
396 	if (node == NULL) {
397 		perror("not enough memory for the inline node");
398 		goto out;
399 	}
400 
401 	INIT_LIST_HEAD(&node->val);
402 	node->addr = addr;
403 
404 	while (getline(&filename, &len, fp) != -1) {
405 		if (filename_split(filename, &line_nr) != 1) {
406 			free(filename);
407 			goto out;
408 		}
409 
410 		if (inline_list__append(filename, NULL, line_nr, node,
411 					NULL) != 0)
412 			goto out;
413 
414 		filename = NULL;
415 	}
416 
417 out:
418 	pclose(fp);
419 
420 	if (list_empty(&node->val)) {
421 		inline_node__delete(node);
422 		return NULL;
423 	}
424 
425 	return node;
426 }
427 
428 #endif /* HAVE_LIBBFD_SUPPORT */
429 
430 /*
431  * Number of addr2line failures (without success) before disabling it for that
432  * dso.
433  */
434 #define A2L_FAIL_LIMIT 123
435 
436 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
437 		  bool show_sym, bool show_addr, bool unwind_inlines)
438 {
439 	char *file = NULL;
440 	unsigned line = 0;
441 	char *srcline;
442 	const char *dso_name;
443 
444 	if (!dso->has_srcline)
445 		goto out;
446 
447 	dso_name = dso__name(dso);
448 	if (dso_name == NULL)
449 		goto out;
450 
451 	if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
452 		goto out;
453 
454 	if (asprintf(&srcline, "%s:%u",
455 				srcline_full_filename ? file : basename(file),
456 				line) < 0) {
457 		free(file);
458 		goto out;
459 	}
460 
461 	dso->a2l_fails = 0;
462 
463 	free(file);
464 	return srcline;
465 
466 out:
467 	if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
468 		dso->has_srcline = 0;
469 		dso__free_a2l(dso);
470 	}
471 
472 	if (!show_addr)
473 		return (show_sym && sym) ?
474 			    strndup(sym->name, sym->namelen) : NULL;
475 
476 	if (sym) {
477 		if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
478 					addr - sym->start) < 0)
479 			return SRCLINE_UNKNOWN;
480 	} else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0)
481 		return SRCLINE_UNKNOWN;
482 	return srcline;
483 }
484 
485 void free_srcline(char *srcline)
486 {
487 	if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
488 		free(srcline);
489 }
490 
491 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
492 		  bool show_sym, bool show_addr)
493 {
494 	return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
495 }
496 
497 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
498 {
499 	const char *dso_name;
500 
501 	dso_name = dso__name(dso);
502 	if (dso_name == NULL)
503 		return NULL;
504 
505 	return addr2inlines(dso_name, addr, dso);
506 }
507 
508 void inline_node__delete(struct inline_node *node)
509 {
510 	struct inline_list *ilist, *tmp;
511 
512 	list_for_each_entry_safe(ilist, tmp, &node->val, list) {
513 		list_del_init(&ilist->list);
514 		zfree(&ilist->filename);
515 		zfree(&ilist->funcname);
516 		free(ilist);
517 	}
518 
519 	free(node);
520 }
521