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