xref: /openbmc/linux/tools/perf/util/srcline.c (revision 9726bfcd)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <inttypes.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 
7 #include <linux/kernel.h>
8 #include <linux/string.h>
9 #include <linux/zalloc.h>
10 
11 #include "util/dso.h"
12 #include "util/debug.h"
13 #include "util/callchain.h"
14 #include "util/symbol_conf.h"
15 #include "srcline.h"
16 #include "string2.h"
17 #include "symbol.h"
18 
19 bool srcline_full_filename;
20 
21 static const char *dso__name(struct dso *dso)
22 {
23 	const char *dso_name;
24 
25 	if (dso->symsrc_filename)
26 		dso_name = dso->symsrc_filename;
27 	else
28 		dso_name = dso->long_name;
29 
30 	if (dso_name[0] == '[')
31 		return NULL;
32 
33 	if (!strncmp(dso_name, "/tmp/perf-", 10))
34 		return NULL;
35 
36 	return dso_name;
37 }
38 
39 static int inline_list__append(struct symbol *symbol, char *srcline,
40 			       struct inline_node *node)
41 {
42 	struct inline_list *ilist;
43 
44 	ilist = zalloc(sizeof(*ilist));
45 	if (ilist == NULL)
46 		return -1;
47 
48 	ilist->symbol = symbol;
49 	ilist->srcline = srcline;
50 
51 	if (callchain_param.order == ORDER_CALLEE)
52 		list_add_tail(&ilist->list, &node->val);
53 	else
54 		list_add(&ilist->list, &node->val);
55 
56 	return 0;
57 }
58 
59 /* basename version that takes a const input string */
60 static const char *gnu_basename(const char *path)
61 {
62 	const char *base = strrchr(path, '/');
63 
64 	return base ? base + 1 : path;
65 }
66 
67 static char *srcline_from_fileline(const char *file, unsigned int line)
68 {
69 	char *srcline;
70 
71 	if (!file)
72 		return NULL;
73 
74 	if (!srcline_full_filename)
75 		file = gnu_basename(file);
76 
77 	if (asprintf(&srcline, "%s:%u", file, line) < 0)
78 		return NULL;
79 
80 	return srcline;
81 }
82 
83 static struct symbol *new_inline_sym(struct dso *dso,
84 				     struct symbol *base_sym,
85 				     const char *funcname)
86 {
87 	struct symbol *inline_sym;
88 	char *demangled = NULL;
89 
90 	if (!funcname)
91 		funcname = "??";
92 
93 	if (dso) {
94 		demangled = dso__demangle_sym(dso, 0, funcname);
95 		if (demangled)
96 			funcname = demangled;
97 	}
98 
99 	if (base_sym && strcmp(funcname, base_sym->name) == 0) {
100 		/* reuse the real, existing symbol */
101 		inline_sym = base_sym;
102 		/* ensure that we don't alias an inlined symbol, which could
103 		 * lead to double frees in inline_node__delete
104 		 */
105 		assert(!base_sym->inlined);
106 	} else {
107 		/* create a fake symbol for the inline frame */
108 		inline_sym = symbol__new(base_sym ? base_sym->start : 0,
109 					 base_sym ? (base_sym->end - base_sym->start) : 0,
110 					 base_sym ? base_sym->binding : 0,
111 					 base_sym ? base_sym->type : 0,
112 					 funcname);
113 		if (inline_sym)
114 			inline_sym->inlined = 1;
115 	}
116 
117 	free(demangled);
118 
119 	return inline_sym;
120 }
121 
122 #ifdef HAVE_LIBBFD_SUPPORT
123 
124 /*
125  * Implement addr2line using libbfd.
126  */
127 #define PACKAGE "perf"
128 #include <bfd.h>
129 
130 struct a2l_data {
131 	const char 	*input;
132 	u64	 	addr;
133 
134 	bool 		found;
135 	const char 	*filename;
136 	const char 	*funcname;
137 	unsigned 	line;
138 
139 	bfd 		*abfd;
140 	asymbol 	**syms;
141 };
142 
143 static int bfd_error(const char *string)
144 {
145 	const char *errmsg;
146 
147 	errmsg = bfd_errmsg(bfd_get_error());
148 	fflush(stdout);
149 
150 	if (string)
151 		pr_debug("%s: %s\n", string, errmsg);
152 	else
153 		pr_debug("%s\n", errmsg);
154 
155 	return -1;
156 }
157 
158 static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
159 {
160 	long storage;
161 	long symcount;
162 	asymbol **syms;
163 	bfd_boolean dynamic = FALSE;
164 
165 	if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
166 		return bfd_error(bfd_get_filename(abfd));
167 
168 	storage = bfd_get_symtab_upper_bound(abfd);
169 	if (storage == 0L) {
170 		storage = bfd_get_dynamic_symtab_upper_bound(abfd);
171 		dynamic = TRUE;
172 	}
173 	if (storage < 0L)
174 		return bfd_error(bfd_get_filename(abfd));
175 
176 	syms = malloc(storage);
177 	if (dynamic)
178 		symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
179 	else
180 		symcount = bfd_canonicalize_symtab(abfd, syms);
181 
182 	if (symcount < 0) {
183 		free(syms);
184 		return bfd_error(bfd_get_filename(abfd));
185 	}
186 
187 	a2l->syms = syms;
188 	return 0;
189 }
190 
191 static void find_address_in_section(bfd *abfd, asection *section, void *data)
192 {
193 	bfd_vma pc, vma;
194 	bfd_size_type size;
195 	struct a2l_data *a2l = data;
196 
197 	if (a2l->found)
198 		return;
199 
200 	if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
201 		return;
202 
203 	pc = a2l->addr;
204 	vma = bfd_get_section_vma(abfd, section);
205 	size = bfd_get_section_size(section);
206 
207 	if (pc < vma || pc >= vma + size)
208 		return;
209 
210 	a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
211 					   &a2l->filename, &a2l->funcname,
212 					   &a2l->line);
213 
214 	if (a2l->filename && !strlen(a2l->filename))
215 		a2l->filename = NULL;
216 }
217 
218 static struct a2l_data *addr2line_init(const char *path)
219 {
220 	bfd *abfd;
221 	struct a2l_data *a2l = NULL;
222 
223 	abfd = bfd_openr(path, NULL);
224 	if (abfd == NULL)
225 		return NULL;
226 
227 	if (!bfd_check_format(abfd, bfd_object))
228 		goto out;
229 
230 	a2l = zalloc(sizeof(*a2l));
231 	if (a2l == NULL)
232 		goto out;
233 
234 	a2l->abfd = abfd;
235 	a2l->input = strdup(path);
236 	if (a2l->input == NULL)
237 		goto out;
238 
239 	if (slurp_symtab(abfd, a2l))
240 		goto out;
241 
242 	return a2l;
243 
244 out:
245 	if (a2l) {
246 		zfree((char **)&a2l->input);
247 		free(a2l);
248 	}
249 	bfd_close(abfd);
250 	return NULL;
251 }
252 
253 static void addr2line_cleanup(struct a2l_data *a2l)
254 {
255 	if (a2l->abfd)
256 		bfd_close(a2l->abfd);
257 	zfree((char **)&a2l->input);
258 	zfree(&a2l->syms);
259 	free(a2l);
260 }
261 
262 #define MAX_INLINE_NEST 1024
263 
264 static int inline_list__append_dso_a2l(struct dso *dso,
265 				       struct inline_node *node,
266 				       struct symbol *sym)
267 {
268 	struct a2l_data *a2l = dso->a2l;
269 	struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname);
270 	char *srcline = NULL;
271 
272 	if (a2l->filename)
273 		srcline = srcline_from_fileline(a2l->filename, a2l->line);
274 
275 	return inline_list__append(inline_sym, srcline, node);
276 }
277 
278 static int addr2line(const char *dso_name, u64 addr,
279 		     char **file, unsigned int *line, struct dso *dso,
280 		     bool unwind_inlines, struct inline_node *node,
281 		     struct symbol *sym)
282 {
283 	int ret = 0;
284 	struct a2l_data *a2l = dso->a2l;
285 
286 	if (!a2l) {
287 		dso->a2l = addr2line_init(dso_name);
288 		a2l = dso->a2l;
289 	}
290 
291 	if (a2l == NULL) {
292 		if (!symbol_conf.disable_add2line_warn)
293 			pr_warning("addr2line_init failed for %s\n", dso_name);
294 		return 0;
295 	}
296 
297 	a2l->addr = addr;
298 	a2l->found = false;
299 
300 	bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
301 
302 	if (!a2l->found)
303 		return 0;
304 
305 	if (unwind_inlines) {
306 		int cnt = 0;
307 
308 		if (node && inline_list__append_dso_a2l(dso, node, sym))
309 			return 0;
310 
311 		while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
312 					     &a2l->funcname, &a2l->line) &&
313 		       cnt++ < MAX_INLINE_NEST) {
314 
315 			if (a2l->filename && !strlen(a2l->filename))
316 				a2l->filename = NULL;
317 
318 			if (node != NULL) {
319 				if (inline_list__append_dso_a2l(dso, node, sym))
320 					return 0;
321 				// found at least one inline frame
322 				ret = 1;
323 			}
324 		}
325 	}
326 
327 	if (file) {
328 		*file = a2l->filename ? strdup(a2l->filename) : NULL;
329 		ret = *file ? 1 : 0;
330 	}
331 
332 	if (line)
333 		*line = a2l->line;
334 
335 	return ret;
336 }
337 
338 void dso__free_a2l(struct dso *dso)
339 {
340 	struct a2l_data *a2l = dso->a2l;
341 
342 	if (!a2l)
343 		return;
344 
345 	addr2line_cleanup(a2l);
346 
347 	dso->a2l = NULL;
348 }
349 
350 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
351 					struct dso *dso, struct symbol *sym)
352 {
353 	struct inline_node *node;
354 
355 	node = zalloc(sizeof(*node));
356 	if (node == NULL) {
357 		perror("not enough memory for the inline node");
358 		return NULL;
359 	}
360 
361 	INIT_LIST_HEAD(&node->val);
362 	node->addr = addr;
363 
364 	addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym);
365 	return node;
366 }
367 
368 #else /* HAVE_LIBBFD_SUPPORT */
369 
370 static int filename_split(char *filename, unsigned int *line_nr)
371 {
372 	char *sep;
373 
374 	sep = strchr(filename, '\n');
375 	if (sep)
376 		*sep = '\0';
377 
378 	if (!strcmp(filename, "??:0"))
379 		return 0;
380 
381 	sep = strchr(filename, ':');
382 	if (sep) {
383 		*sep++ = '\0';
384 		*line_nr = strtoul(sep, NULL, 0);
385 		return 1;
386 	}
387 
388 	return 0;
389 }
390 
391 static int addr2line(const char *dso_name, u64 addr,
392 		     char **file, unsigned int *line_nr,
393 		     struct dso *dso __maybe_unused,
394 		     bool unwind_inlines __maybe_unused,
395 		     struct inline_node *node __maybe_unused,
396 		     struct symbol *sym __maybe_unused)
397 {
398 	FILE *fp;
399 	char cmd[PATH_MAX];
400 	char *filename = NULL;
401 	size_t len;
402 	int ret = 0;
403 
404 	scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
405 		  dso_name, addr);
406 
407 	fp = popen(cmd, "r");
408 	if (fp == NULL) {
409 		pr_warning("popen failed for %s\n", dso_name);
410 		return 0;
411 	}
412 
413 	if (getline(&filename, &len, fp) < 0 || !len) {
414 		pr_warning("addr2line has no output for %s\n", dso_name);
415 		goto out;
416 	}
417 
418 	ret = filename_split(filename, line_nr);
419 	if (ret != 1) {
420 		free(filename);
421 		goto out;
422 	}
423 
424 	*file = filename;
425 
426 out:
427 	pclose(fp);
428 	return ret;
429 }
430 
431 void dso__free_a2l(struct dso *dso __maybe_unused)
432 {
433 }
434 
435 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
436 					struct dso *dso __maybe_unused,
437 					struct symbol *sym)
438 {
439 	FILE *fp;
440 	char cmd[PATH_MAX];
441 	struct inline_node *node;
442 	char *filename = NULL;
443 	char *funcname = NULL;
444 	size_t filelen, funclen;
445 	unsigned int line_nr = 0;
446 
447 	scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i -f %016"PRIx64,
448 		  dso_name, addr);
449 
450 	fp = popen(cmd, "r");
451 	if (fp == NULL) {
452 		pr_err("popen failed for %s\n", dso_name);
453 		return NULL;
454 	}
455 
456 	node = zalloc(sizeof(*node));
457 	if (node == NULL) {
458 		perror("not enough memory for the inline node");
459 		goto out;
460 	}
461 
462 	INIT_LIST_HEAD(&node->val);
463 	node->addr = addr;
464 
465 	/* addr2line -f generates two lines for each inlined functions */
466 	while (getline(&funcname, &funclen, fp) != -1) {
467 		char *srcline;
468 		struct symbol *inline_sym;
469 
470 		strim(funcname);
471 
472 		if (getline(&filename, &filelen, fp) == -1)
473 			goto out;
474 
475 		if (filename_split(filename, &line_nr) != 1)
476 			goto out;
477 
478 		srcline = srcline_from_fileline(filename, line_nr);
479 		inline_sym = new_inline_sym(dso, sym, funcname);
480 
481 		if (inline_list__append(inline_sym, srcline, node) != 0) {
482 			free(srcline);
483 			if (inline_sym && inline_sym->inlined)
484 				symbol__delete(inline_sym);
485 			goto out;
486 		}
487 	}
488 
489 out:
490 	pclose(fp);
491 	free(filename);
492 	free(funcname);
493 
494 	return node;
495 }
496 
497 #endif /* HAVE_LIBBFD_SUPPORT */
498 
499 /*
500  * Number of addr2line failures (without success) before disabling it for that
501  * dso.
502  */
503 #define A2L_FAIL_LIMIT 123
504 
505 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
506 		  bool show_sym, bool show_addr, bool unwind_inlines,
507 		  u64 ip)
508 {
509 	char *file = NULL;
510 	unsigned line = 0;
511 	char *srcline;
512 	const char *dso_name;
513 
514 	if (!dso->has_srcline)
515 		goto out;
516 
517 	dso_name = dso__name(dso);
518 	if (dso_name == NULL)
519 		goto out;
520 
521 	if (!addr2line(dso_name, addr, &file, &line, dso,
522 		       unwind_inlines, NULL, sym))
523 		goto out;
524 
525 	srcline = srcline_from_fileline(file, line);
526 	free(file);
527 
528 	if (!srcline)
529 		goto out;
530 
531 	dso->a2l_fails = 0;
532 
533 	return srcline;
534 
535 out:
536 	if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
537 		dso->has_srcline = 0;
538 		dso__free_a2l(dso);
539 	}
540 
541 	if (!show_addr)
542 		return (show_sym && sym) ?
543 			    strndup(sym->name, sym->namelen) : NULL;
544 
545 	if (sym) {
546 		if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
547 					ip - sym->start) < 0)
548 			return SRCLINE_UNKNOWN;
549 	} else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0)
550 		return SRCLINE_UNKNOWN;
551 	return srcline;
552 }
553 
554 /* Returns filename and fills in line number in line */
555 char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
556 {
557 	char *file = NULL;
558 	const char *dso_name;
559 
560 	if (!dso->has_srcline)
561 		goto out;
562 
563 	dso_name = dso__name(dso);
564 	if (dso_name == NULL)
565 		goto out;
566 
567 	if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL))
568 		goto out;
569 
570 	dso->a2l_fails = 0;
571 	return file;
572 
573 out:
574 	if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
575 		dso->has_srcline = 0;
576 		dso__free_a2l(dso);
577 	}
578 
579 	return NULL;
580 }
581 
582 void free_srcline(char *srcline)
583 {
584 	if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
585 		free(srcline);
586 }
587 
588 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
589 		  bool show_sym, bool show_addr, u64 ip)
590 {
591 	return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip);
592 }
593 
594 struct srcline_node {
595 	u64			addr;
596 	char			*srcline;
597 	struct rb_node		rb_node;
598 };
599 
600 void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline)
601 {
602 	struct rb_node **p = &tree->rb_root.rb_node;
603 	struct rb_node *parent = NULL;
604 	struct srcline_node *i, *node;
605 	bool leftmost = true;
606 
607 	node = zalloc(sizeof(struct srcline_node));
608 	if (!node) {
609 		perror("not enough memory for the srcline node");
610 		return;
611 	}
612 
613 	node->addr = addr;
614 	node->srcline = srcline;
615 
616 	while (*p != NULL) {
617 		parent = *p;
618 		i = rb_entry(parent, struct srcline_node, rb_node);
619 		if (addr < i->addr)
620 			p = &(*p)->rb_left;
621 		else {
622 			p = &(*p)->rb_right;
623 			leftmost = false;
624 		}
625 	}
626 	rb_link_node(&node->rb_node, parent, p);
627 	rb_insert_color_cached(&node->rb_node, tree, leftmost);
628 }
629 
630 char *srcline__tree_find(struct rb_root_cached *tree, u64 addr)
631 {
632 	struct rb_node *n = tree->rb_root.rb_node;
633 
634 	while (n) {
635 		struct srcline_node *i = rb_entry(n, struct srcline_node,
636 						  rb_node);
637 
638 		if (addr < i->addr)
639 			n = n->rb_left;
640 		else if (addr > i->addr)
641 			n = n->rb_right;
642 		else
643 			return i->srcline;
644 	}
645 
646 	return NULL;
647 }
648 
649 void srcline__tree_delete(struct rb_root_cached *tree)
650 {
651 	struct srcline_node *pos;
652 	struct rb_node *next = rb_first_cached(tree);
653 
654 	while (next) {
655 		pos = rb_entry(next, struct srcline_node, rb_node);
656 		next = rb_next(&pos->rb_node);
657 		rb_erase_cached(&pos->rb_node, tree);
658 		free_srcline(pos->srcline);
659 		zfree(&pos);
660 	}
661 }
662 
663 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
664 					    struct symbol *sym)
665 {
666 	const char *dso_name;
667 
668 	dso_name = dso__name(dso);
669 	if (dso_name == NULL)
670 		return NULL;
671 
672 	return addr2inlines(dso_name, addr, dso, sym);
673 }
674 
675 void inline_node__delete(struct inline_node *node)
676 {
677 	struct inline_list *ilist, *tmp;
678 
679 	list_for_each_entry_safe(ilist, tmp, &node->val, list) {
680 		list_del_init(&ilist->list);
681 		free_srcline(ilist->srcline);
682 		/* only the inlined symbols are owned by the list */
683 		if (ilist->symbol && ilist->symbol->inlined)
684 			symbol__delete(ilist->symbol);
685 		free(ilist);
686 	}
687 
688 	free(node);
689 }
690 
691 void inlines__tree_insert(struct rb_root_cached *tree,
692 			  struct inline_node *inlines)
693 {
694 	struct rb_node **p = &tree->rb_root.rb_node;
695 	struct rb_node *parent = NULL;
696 	const u64 addr = inlines->addr;
697 	struct inline_node *i;
698 	bool leftmost = true;
699 
700 	while (*p != NULL) {
701 		parent = *p;
702 		i = rb_entry(parent, struct inline_node, rb_node);
703 		if (addr < i->addr)
704 			p = &(*p)->rb_left;
705 		else {
706 			p = &(*p)->rb_right;
707 			leftmost = false;
708 		}
709 	}
710 	rb_link_node(&inlines->rb_node, parent, p);
711 	rb_insert_color_cached(&inlines->rb_node, tree, leftmost);
712 }
713 
714 struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr)
715 {
716 	struct rb_node *n = tree->rb_root.rb_node;
717 
718 	while (n) {
719 		struct inline_node *i = rb_entry(n, struct inline_node,
720 						 rb_node);
721 
722 		if (addr < i->addr)
723 			n = n->rb_left;
724 		else if (addr > i->addr)
725 			n = n->rb_right;
726 		else
727 			return i;
728 	}
729 
730 	return NULL;
731 }
732 
733 void inlines__tree_delete(struct rb_root_cached *tree)
734 {
735 	struct inline_node *pos;
736 	struct rb_node *next = rb_first_cached(tree);
737 
738 	while (next) {
739 		pos = rb_entry(next, struct inline_node, rb_node);
740 		next = rb_next(&pos->rb_node);
741 		rb_erase_cached(&pos->rb_node, tree);
742 		inline_node__delete(pos);
743 	}
744 }
745