xref: /linux/tools/perf/util/srcline.c (revision 19a9ed115fda95317c98bef0c716ea8412cd8ce0)
1 // SPDX-License-Identifier: GPL-2.0
2 #include "srcline.h"
3 #include "addr2line.h"
4 #include "dso.h"
5 #include "callchain.h"
6 #include "libbfd.h"
7 #include "llvm.h"
8 #include "symbol.h"
9 #include "libdw.h"
10 #include "debug.h"
11 #include "util.h"
12 
13 #include <inttypes.h>
14 #include <string.h>
15 #include <linux/string.h>
16 #include <linux/zalloc.h>
17 
18 bool srcline_full_filename;
19 
20 char *srcline__unknown = (char *)"??:0";
21 
22 static const char *srcline_dso_name(struct dso *dso)
23 {
24 	const char *dso_name;
25 
26 	if (dso__symsrc_filename(dso))
27 		dso_name = dso__symsrc_filename(dso);
28 	else
29 		dso_name = dso__long_name(dso);
30 
31 	if (dso_name[0] == '[')
32 		return NULL;
33 
34 	if (is_perf_pid_map_name(dso_name))
35 		return NULL;
36 
37 	return dso_name;
38 }
39 
40 int inline_list__append(struct symbol *symbol, char *srcline, 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 int inline_list__append_tail(struct symbol *symbol, char *srcline, struct inline_node *node)
60 {
61 	struct inline_list *ilist;
62 
63 	ilist = zalloc(sizeof(*ilist));
64 	if (ilist == NULL)
65 		return -1;
66 
67 	ilist->symbol = symbol;
68 	ilist->srcline = srcline;
69 
70 	if (callchain_param.order == ORDER_CALLEE)
71 		list_add(&ilist->list, &node->val);
72 	else
73 		list_add_tail(&ilist->list, &node->val);
74 
75 	return 0;
76 }
77 
78 char *srcline_from_fileline(const char *file, unsigned int line)
79 {
80 	char *srcline;
81 
82 	if (!file)
83 		return NULL;
84 
85 	if (!srcline_full_filename)
86 		file = perf_basename(file);
87 
88 	if (asprintf(&srcline, "%s:%u", file, line) < 0)
89 		return NULL;
90 
91 	return srcline;
92 }
93 
94 struct symbol *new_inline_sym(struct dso *dso,
95 			      struct symbol *base_sym,
96 			      const char *funcname)
97 {
98 	struct symbol *inline_sym;
99 	char *demangled = NULL;
100 
101 	if (!funcname)
102 		funcname = "??";
103 
104 	if (dso) {
105 		demangled = dso__demangle_sym(dso, 0, funcname);
106 		if (demangled)
107 			funcname = demangled;
108 	}
109 
110 	if (base_sym && strcmp(funcname, base_sym->name) == 0) {
111 		/* reuse the real, existing symbol */
112 		inline_sym = base_sym;
113 		/* ensure that we don't alias an inlined symbol, which could
114 		 * lead to double frees in inline_node__delete
115 		 */
116 		assert(!base_sym->inlined);
117 	} else {
118 		/* create a fake symbol for the inline frame */
119 		inline_sym = symbol__new(base_sym ? base_sym->start : 0,
120 					 base_sym ? (base_sym->end - base_sym->start) : 0,
121 					 base_sym ? base_sym->binding : 0,
122 					 base_sym ? base_sym->type : 0,
123 					 funcname);
124 		if (inline_sym)
125 			inline_sym->inlined = 1;
126 	}
127 
128 	free(demangled);
129 
130 	return inline_sym;
131 }
132 
133 static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr,
134 		     struct dso *dso, bool unwind_inlines, struct inline_node *node,
135 		     struct symbol *sym)
136 {
137 	int ret = 0;
138 
139 	if (symbol_conf.addr2line_style[0] == A2L_STYLE_UNKNOWN) {
140 		int i = 0;
141 
142 		/* Default addr2line fallback order. */
143 #ifdef HAVE_LIBDW_SUPPORT
144 		symbol_conf.addr2line_style[i++] = A2L_STYLE_LIBDW;
145 #endif
146 #ifdef HAVE_LIBLLVM_SUPPORT
147 		symbol_conf.addr2line_style[i++] = A2L_STYLE_LLVM;
148 #endif
149 #ifdef HAVE_LIBBFD_SUPPORT
150 		symbol_conf.addr2line_style[i++] = A2L_STYLE_LIBBFD;
151 #endif
152 		symbol_conf.addr2line_style[i++] = A2L_STYLE_CMD;
153 	}
154 
155 	for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.addr2line_style); i++) {
156 		switch (symbol_conf.addr2line_style[i]) {
157 		case A2L_STYLE_LIBDW:
158 			ret = libdw__addr2line(addr, file, line_nr, dso, unwind_inlines,
159 					       node, sym);
160 			break;
161 		case A2L_STYLE_LLVM:
162 			ret = llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines,
163 					      node, sym);
164 			break;
165 		case A2L_STYLE_LIBBFD:
166 			ret = libbfd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines,
167 						node, sym);
168 			break;
169 		case A2L_STYLE_CMD:
170 			ret = cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines,
171 					     node, sym);
172 			break;
173 		case A2L_STYLE_UNKNOWN:
174 		default:
175 			break;
176 		}
177 		if (ret > 0)
178 			return ret;
179 	}
180 
181 	return 0;
182 }
183 
184 int addr2line_configure(const char *var, const char *value, void *cb __maybe_unused)
185 {
186 	static const char * const a2l_style_names[] = {
187 		[A2L_STYLE_LIBDW] = "libdw",
188 		[A2L_STYLE_LLVM] = "llvm",
189 		[A2L_STYLE_LIBBFD] = "libbfd",
190 		[A2L_STYLE_CMD] = "addr2line",
191 		NULL
192 	};
193 
194 	char *s, *p, *saveptr;
195 	size_t i = 0;
196 
197 	if (strcmp(var, "addr2line.style"))
198 		return 0;
199 
200 	if (!value)
201 		return -1;
202 
203 	s = strdup(value);
204 	if (!s)
205 		return -1;
206 
207 	p = strtok_r(s, ",", &saveptr);
208 	while (p && i < ARRAY_SIZE(symbol_conf.addr2line_style)) {
209 		bool found = false;
210 		char *q = strim(p);
211 
212 		for (size_t j = A2L_STYLE_LIBDW; j < MAX_A2L_STYLE; j++) {
213 			if (!strcasecmp(q, a2l_style_names[j])) {
214 				symbol_conf.addr2line_style[i++] = j;
215 				found = true;
216 				break;
217 			}
218 		}
219 		if (!found)
220 			pr_warning("Unknown addr2line style: %s\n", q);
221 		p = strtok_r(NULL, ",", &saveptr);
222 	}
223 
224 	free(s);
225 	return 0;
226 }
227 
228 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
229 					struct dso *dso, struct symbol *sym)
230 {
231 	struct inline_node *node;
232 
233 	node = zalloc(sizeof(*node));
234 	if (node == NULL) {
235 		perror("not enough memory for the inline node");
236 		return NULL;
237 	}
238 
239 	INIT_LIST_HEAD(&node->val);
240 	node->addr = addr;
241 
242 	addr2line(dso_name, addr, /*file=*/NULL, /*line_nr=*/NULL, dso,
243 		  /*unwind_inlines=*/true, node, sym);
244 
245 	return node;
246 }
247 
248 /*
249  * Number of addr2line failures (without success) before disabling it for that
250  * dso.
251  */
252 #define A2L_FAIL_LIMIT 123
253 
254 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
255 		  bool show_sym, bool show_addr, bool unwind_inlines,
256 		  u64 ip)
257 {
258 	char *file = NULL;
259 	unsigned line = 0;
260 	char *srcline;
261 	const char *dso_name;
262 
263 	if (!dso__has_srcline(dso))
264 		goto out;
265 
266 	dso_name = srcline_dso_name(dso);
267 	if (dso_name == NULL)
268 		goto out_err;
269 
270 	if (!addr2line(dso_name, addr, &file, &line, dso,
271 		       unwind_inlines, /*node=*/NULL, sym))
272 		goto out_err;
273 
274 	srcline = srcline_from_fileline(file, line);
275 	free(file);
276 
277 	if (!srcline)
278 		goto out_err;
279 
280 	dso__set_a2l_fails(dso, 0);
281 
282 	return srcline;
283 
284 out_err:
285 	dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1);
286 	if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) {
287 		dso__set_has_srcline(dso, false);
288 		dso__free_a2l(dso);
289 	}
290 out:
291 	if (!show_addr)
292 		return (show_sym && sym) ?
293 			    strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN;
294 
295 	if (sym) {
296 		if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
297 					ip - sym->start) < 0)
298 			return SRCLINE_UNKNOWN;
299 	} else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso__short_name(dso), addr) < 0)
300 		return SRCLINE_UNKNOWN;
301 	return srcline;
302 }
303 
304 /* Returns filename and fills in line number in line */
305 char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
306 {
307 	char *file = NULL;
308 	const char *dso_name;
309 
310 	if (!dso__has_srcline(dso))
311 		return NULL;
312 
313 	dso_name = srcline_dso_name(dso);
314 	if (dso_name == NULL)
315 		goto out_err;
316 
317 	if (!addr2line(dso_name, addr, &file, line, dso, /*unwind_inlines=*/true,
318 			/*node=*/NULL, /*sym=*/NULL))
319 		goto out_err;
320 
321 	dso__set_a2l_fails(dso, 0);
322 	return file;
323 
324 out_err:
325 	dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1);
326 	if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) {
327 		dso__set_has_srcline(dso, false);
328 		dso__free_a2l(dso);
329 	}
330 
331 	return NULL;
332 }
333 
334 void zfree_srcline(char **srcline)
335 {
336 	if (*srcline == NULL)
337 		return;
338 
339 	if (*srcline != SRCLINE_UNKNOWN)
340 		free(*srcline);
341 
342 	*srcline = NULL;
343 }
344 
345 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
346 		  bool show_sym, bool show_addr, u64 ip)
347 {
348 	return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip);
349 }
350 
351 struct srcline_node {
352 	u64			addr;
353 	char			*srcline;
354 	struct rb_node		rb_node;
355 };
356 
357 void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline)
358 {
359 	struct rb_node **p = &tree->rb_root.rb_node;
360 	struct rb_node *parent = NULL;
361 	struct srcline_node *i, *node;
362 	bool leftmost = true;
363 
364 	node = zalloc(sizeof(struct srcline_node));
365 	if (!node) {
366 		perror("not enough memory for the srcline node");
367 		return;
368 	}
369 
370 	node->addr = addr;
371 	node->srcline = srcline;
372 
373 	while (*p != NULL) {
374 		parent = *p;
375 		i = rb_entry(parent, struct srcline_node, rb_node);
376 		if (addr < i->addr)
377 			p = &(*p)->rb_left;
378 		else {
379 			p = &(*p)->rb_right;
380 			leftmost = false;
381 		}
382 	}
383 	rb_link_node(&node->rb_node, parent, p);
384 	rb_insert_color_cached(&node->rb_node, tree, leftmost);
385 }
386 
387 char *srcline__tree_find(struct rb_root_cached *tree, u64 addr)
388 {
389 	struct rb_node *n = tree->rb_root.rb_node;
390 
391 	while (n) {
392 		struct srcline_node *i = rb_entry(n, struct srcline_node,
393 						  rb_node);
394 
395 		if (addr < i->addr)
396 			n = n->rb_left;
397 		else if (addr > i->addr)
398 			n = n->rb_right;
399 		else
400 			return i->srcline;
401 	}
402 
403 	return NULL;
404 }
405 
406 void srcline__tree_delete(struct rb_root_cached *tree)
407 {
408 	struct srcline_node *pos;
409 	struct rb_node *next = rb_first_cached(tree);
410 
411 	while (next) {
412 		pos = rb_entry(next, struct srcline_node, rb_node);
413 		next = rb_next(&pos->rb_node);
414 		rb_erase_cached(&pos->rb_node, tree);
415 		zfree_srcline(&pos->srcline);
416 		zfree(&pos);
417 	}
418 }
419 
420 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
421 					    struct symbol *sym)
422 {
423 	const char *dso_name;
424 
425 	dso_name = srcline_dso_name(dso);
426 	if (dso_name == NULL)
427 		return NULL;
428 
429 	return addr2inlines(dso_name, addr, dso, sym);
430 }
431 
432 void inline_node__delete(struct inline_node *node)
433 {
434 	struct inline_list *ilist, *tmp;
435 
436 	list_for_each_entry_safe(ilist, tmp, &node->val, list) {
437 		list_del_init(&ilist->list);
438 		zfree_srcline(&ilist->srcline);
439 		/* only the inlined symbols are owned by the list */
440 		if (ilist->symbol && ilist->symbol->inlined)
441 			symbol__delete(ilist->symbol);
442 		free(ilist);
443 	}
444 
445 	free(node);
446 }
447 
448 void inlines__tree_insert(struct rb_root_cached *tree,
449 			  struct inline_node *inlines)
450 {
451 	struct rb_node **p = &tree->rb_root.rb_node;
452 	struct rb_node *parent = NULL;
453 	const u64 addr = inlines->addr;
454 	struct inline_node *i;
455 	bool leftmost = true;
456 
457 	while (*p != NULL) {
458 		parent = *p;
459 		i = rb_entry(parent, struct inline_node, rb_node);
460 		if (addr < i->addr)
461 			p = &(*p)->rb_left;
462 		else {
463 			p = &(*p)->rb_right;
464 			leftmost = false;
465 		}
466 	}
467 	rb_link_node(&inlines->rb_node, parent, p);
468 	rb_insert_color_cached(&inlines->rb_node, tree, leftmost);
469 }
470 
471 struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr)
472 {
473 	struct rb_node *n = tree->rb_root.rb_node;
474 
475 	while (n) {
476 		struct inline_node *i = rb_entry(n, struct inline_node,
477 						 rb_node);
478 
479 		if (addr < i->addr)
480 			n = n->rb_left;
481 		else if (addr > i->addr)
482 			n = n->rb_right;
483 		else
484 			return i;
485 	}
486 
487 	return NULL;
488 }
489 
490 void inlines__tree_delete(struct rb_root_cached *tree)
491 {
492 	struct inline_node *pos;
493 	struct rb_node *next = rb_first_cached(tree);
494 
495 	while (next) {
496 		pos = rb_entry(next, struct inline_node, rb_node);
497 		next = rb_next(&pos->rb_node);
498 		rb_erase_cached(&pos->rb_node, tree);
499 		inline_node__delete(pos);
500 	}
501 }
502