xref: /openbmc/linux/tools/perf/util/srcline.c (revision 5a244f48)
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 	if (a2l->filename && !strlen(a2l->filename))
160 		a2l->filename = NULL;
161 }
162 
163 static struct a2l_data *addr2line_init(const char *path)
164 {
165 	bfd *abfd;
166 	struct a2l_data *a2l = NULL;
167 
168 	abfd = bfd_openr(path, NULL);
169 	if (abfd == NULL)
170 		return NULL;
171 
172 	if (!bfd_check_format(abfd, bfd_object))
173 		goto out;
174 
175 	a2l = zalloc(sizeof(*a2l));
176 	if (a2l == NULL)
177 		goto out;
178 
179 	a2l->abfd = abfd;
180 	a2l->input = strdup(path);
181 	if (a2l->input == NULL)
182 		goto out;
183 
184 	if (slurp_symtab(abfd, a2l))
185 		goto out;
186 
187 	return a2l;
188 
189 out:
190 	if (a2l) {
191 		zfree((char **)&a2l->input);
192 		free(a2l);
193 	}
194 	bfd_close(abfd);
195 	return NULL;
196 }
197 
198 static void addr2line_cleanup(struct a2l_data *a2l)
199 {
200 	if (a2l->abfd)
201 		bfd_close(a2l->abfd);
202 	zfree((char **)&a2l->input);
203 	zfree(&a2l->syms);
204 	free(a2l);
205 }
206 
207 #define MAX_INLINE_NEST 1024
208 
209 static int inline_list__append_dso_a2l(struct dso *dso,
210 				       struct inline_node *node)
211 {
212 	struct a2l_data *a2l = dso->a2l;
213 	char *funcname = a2l->funcname ? strdup(a2l->funcname) : NULL;
214 	char *filename = a2l->filename ? strdup(a2l->filename) : NULL;
215 
216 	return inline_list__append(filename, funcname, a2l->line, node, dso);
217 }
218 
219 static int addr2line(const char *dso_name, u64 addr,
220 		     char **file, unsigned int *line, struct dso *dso,
221 		     bool unwind_inlines, struct inline_node *node)
222 {
223 	int ret = 0;
224 	struct a2l_data *a2l = dso->a2l;
225 
226 	if (!a2l) {
227 		dso->a2l = addr2line_init(dso_name);
228 		a2l = dso->a2l;
229 	}
230 
231 	if (a2l == NULL) {
232 		pr_warning("addr2line_init failed for %s\n", dso_name);
233 		return 0;
234 	}
235 
236 	a2l->addr = addr;
237 	a2l->found = false;
238 
239 	bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
240 
241 	if (!a2l->found)
242 		return 0;
243 
244 	if (unwind_inlines) {
245 		int cnt = 0;
246 
247 		if (node && inline_list__append_dso_a2l(dso, node))
248 			return 0;
249 
250 		while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
251 					     &a2l->funcname, &a2l->line) &&
252 		       cnt++ < MAX_INLINE_NEST) {
253 
254 			if (a2l->filename && !strlen(a2l->filename))
255 				a2l->filename = NULL;
256 
257 			if (node != NULL) {
258 				if (inline_list__append_dso_a2l(dso, node))
259 					return 0;
260 				// found at least one inline frame
261 				ret = 1;
262 			}
263 		}
264 	}
265 
266 	if (file) {
267 		*file = a2l->filename ? strdup(a2l->filename) : NULL;
268 		ret = *file ? 1 : 0;
269 	}
270 
271 	if (line)
272 		*line = a2l->line;
273 
274 	return ret;
275 }
276 
277 void dso__free_a2l(struct dso *dso)
278 {
279 	struct a2l_data *a2l = dso->a2l;
280 
281 	if (!a2l)
282 		return;
283 
284 	addr2line_cleanup(a2l);
285 
286 	dso->a2l = NULL;
287 }
288 
289 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
290 	struct dso *dso)
291 {
292 	struct inline_node *node;
293 
294 	node = zalloc(sizeof(*node));
295 	if (node == NULL) {
296 		perror("not enough memory for the inline node");
297 		return NULL;
298 	}
299 
300 	INIT_LIST_HEAD(&node->val);
301 	node->addr = addr;
302 
303 	if (!addr2line(dso_name, addr, NULL, NULL, dso, TRUE, node))
304 		goto out_free_inline_node;
305 
306 	if (list_empty(&node->val))
307 		goto out_free_inline_node;
308 
309 	return node;
310 
311 out_free_inline_node:
312 	inline_node__delete(node);
313 	return NULL;
314 }
315 
316 #else /* HAVE_LIBBFD_SUPPORT */
317 
318 static int filename_split(char *filename, unsigned int *line_nr)
319 {
320 	char *sep;
321 
322 	sep = strchr(filename, '\n');
323 	if (sep)
324 		*sep = '\0';
325 
326 	if (!strcmp(filename, "??:0"))
327 		return 0;
328 
329 	sep = strchr(filename, ':');
330 	if (sep) {
331 		*sep++ = '\0';
332 		*line_nr = strtoul(sep, NULL, 0);
333 		return 1;
334 	}
335 
336 	return 0;
337 }
338 
339 static int addr2line(const char *dso_name, u64 addr,
340 		     char **file, unsigned int *line_nr,
341 		     struct dso *dso __maybe_unused,
342 		     bool unwind_inlines __maybe_unused,
343 		     struct inline_node *node __maybe_unused)
344 {
345 	FILE *fp;
346 	char cmd[PATH_MAX];
347 	char *filename = NULL;
348 	size_t len;
349 	int ret = 0;
350 
351 	scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
352 		  dso_name, addr);
353 
354 	fp = popen(cmd, "r");
355 	if (fp == NULL) {
356 		pr_warning("popen failed for %s\n", dso_name);
357 		return 0;
358 	}
359 
360 	if (getline(&filename, &len, fp) < 0 || !len) {
361 		pr_warning("addr2line has no output for %s\n", dso_name);
362 		goto out;
363 	}
364 
365 	ret = filename_split(filename, line_nr);
366 	if (ret != 1) {
367 		free(filename);
368 		goto out;
369 	}
370 
371 	*file = filename;
372 
373 out:
374 	pclose(fp);
375 	return ret;
376 }
377 
378 void dso__free_a2l(struct dso *dso __maybe_unused)
379 {
380 }
381 
382 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
383 	struct dso *dso __maybe_unused)
384 {
385 	FILE *fp;
386 	char cmd[PATH_MAX];
387 	struct inline_node *node;
388 	char *filename = NULL;
389 	size_t len;
390 	unsigned int line_nr = 0;
391 
392 	scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
393 		  dso_name, addr);
394 
395 	fp = popen(cmd, "r");
396 	if (fp == NULL) {
397 		pr_err("popen failed for %s\n", dso_name);
398 		return NULL;
399 	}
400 
401 	node = zalloc(sizeof(*node));
402 	if (node == NULL) {
403 		perror("not enough memory for the inline node");
404 		goto out;
405 	}
406 
407 	INIT_LIST_HEAD(&node->val);
408 	node->addr = addr;
409 
410 	while (getline(&filename, &len, fp) != -1) {
411 		if (filename_split(filename, &line_nr) != 1) {
412 			free(filename);
413 			goto out;
414 		}
415 
416 		if (inline_list__append(filename, NULL, line_nr, node,
417 					NULL) != 0)
418 			goto out;
419 
420 		filename = NULL;
421 	}
422 
423 out:
424 	pclose(fp);
425 
426 	if (list_empty(&node->val)) {
427 		inline_node__delete(node);
428 		return NULL;
429 	}
430 
431 	return node;
432 }
433 
434 #endif /* HAVE_LIBBFD_SUPPORT */
435 
436 /*
437  * Number of addr2line failures (without success) before disabling it for that
438  * dso.
439  */
440 #define A2L_FAIL_LIMIT 123
441 
442 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
443 		  bool show_sym, bool show_addr, bool unwind_inlines)
444 {
445 	char *file = NULL;
446 	unsigned line = 0;
447 	char *srcline;
448 	const char *dso_name;
449 
450 	if (!dso->has_srcline)
451 		goto out;
452 
453 	dso_name = dso__name(dso);
454 	if (dso_name == NULL)
455 		goto out;
456 
457 	if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
458 		goto out;
459 
460 	if (asprintf(&srcline, "%s:%u",
461 				srcline_full_filename ? file : basename(file),
462 				line) < 0) {
463 		free(file);
464 		goto out;
465 	}
466 
467 	dso->a2l_fails = 0;
468 
469 	free(file);
470 	return srcline;
471 
472 out:
473 	if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
474 		dso->has_srcline = 0;
475 		dso__free_a2l(dso);
476 	}
477 
478 	if (!show_addr)
479 		return (show_sym && sym) ?
480 			    strndup(sym->name, sym->namelen) : NULL;
481 
482 	if (sym) {
483 		if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
484 					addr - sym->start) < 0)
485 			return SRCLINE_UNKNOWN;
486 	} else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0)
487 		return SRCLINE_UNKNOWN;
488 	return srcline;
489 }
490 
491 void free_srcline(char *srcline)
492 {
493 	if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
494 		free(srcline);
495 }
496 
497 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
498 		  bool show_sym, bool show_addr)
499 {
500 	return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
501 }
502 
503 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
504 {
505 	const char *dso_name;
506 
507 	dso_name = dso__name(dso);
508 	if (dso_name == NULL)
509 		return NULL;
510 
511 	return addr2inlines(dso_name, addr, dso);
512 }
513 
514 void inline_node__delete(struct inline_node *node)
515 {
516 	struct inline_list *ilist, *tmp;
517 
518 	list_for_each_entry_safe(ilist, tmp, &node->val, list) {
519 		list_del_init(&ilist->list);
520 		zfree(&ilist->filename);
521 		zfree(&ilist->funcname);
522 		free(ilist);
523 	}
524 
525 	free(node);
526 }
527