1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <inttypes.h> |
3 | #include <signal.h> |
4 | #include <stdio.h> |
5 | #include <stdlib.h> |
6 | #include <string.h> |
7 | #include <sys/types.h> |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/string.h> |
11 | #include <linux/zalloc.h> |
12 | |
13 | #include <api/io.h> |
14 | |
15 | #include "util/dso.h" |
16 | #include "util/debug.h" |
17 | #include "util/callchain.h" |
18 | #include "util/symbol_conf.h" |
19 | #include "srcline.h" |
20 | #include "string2.h" |
21 | #include "symbol.h" |
22 | #include "subcmd/run-command.h" |
23 | |
24 | /* If addr2line doesn't return data for 1 second then timeout. */ |
25 | int addr2line_timeout_ms = 1 * 1000; |
26 | bool srcline_full_filename; |
27 | |
28 | char *srcline__unknown = (char *)"??:0" ; |
29 | |
30 | static const char *dso__name(struct dso *dso) |
31 | { |
32 | const char *dso_name; |
33 | |
34 | if (dso->symsrc_filename) |
35 | dso_name = dso->symsrc_filename; |
36 | else |
37 | dso_name = dso->long_name; |
38 | |
39 | if (dso_name[0] == '[') |
40 | return NULL; |
41 | |
42 | if (!strncmp(dso_name, "/tmp/perf-" , 10)) |
43 | return NULL; |
44 | |
45 | return dso_name; |
46 | } |
47 | |
48 | static int inline_list__append(struct symbol *symbol, char *srcline, |
49 | struct inline_node *node) |
50 | { |
51 | struct inline_list *ilist; |
52 | |
53 | ilist = zalloc(sizeof(*ilist)); |
54 | if (ilist == NULL) |
55 | return -1; |
56 | |
57 | ilist->symbol = symbol; |
58 | ilist->srcline = srcline; |
59 | |
60 | if (callchain_param.order == ORDER_CALLEE) |
61 | list_add_tail(new: &ilist->list, head: &node->val); |
62 | else |
63 | list_add(new: &ilist->list, head: &node->val); |
64 | |
65 | return 0; |
66 | } |
67 | |
68 | /* basename version that takes a const input string */ |
69 | static const char *gnu_basename(const char *path) |
70 | { |
71 | const char *base = strrchr(path, '/'); |
72 | |
73 | return base ? base + 1 : path; |
74 | } |
75 | |
76 | static char *srcline_from_fileline(const char *file, unsigned int line) |
77 | { |
78 | char *srcline; |
79 | |
80 | if (!file) |
81 | return NULL; |
82 | |
83 | if (!srcline_full_filename) |
84 | file = gnu_basename(path: file); |
85 | |
86 | if (asprintf(&srcline, "%s:%u" , file, line) < 0) |
87 | return NULL; |
88 | |
89 | return srcline; |
90 | } |
91 | |
92 | static struct symbol *new_inline_sym(struct dso *dso, |
93 | struct symbol *base_sym, |
94 | const char *funcname) |
95 | { |
96 | struct symbol *inline_sym; |
97 | char *demangled = NULL; |
98 | |
99 | if (!funcname) |
100 | funcname = "??" ; |
101 | |
102 | if (dso) { |
103 | demangled = dso__demangle_sym(dso, kmodule: 0, elf_name: funcname); |
104 | if (demangled) |
105 | funcname = demangled; |
106 | } |
107 | |
108 | if (base_sym && strcmp(funcname, base_sym->name) == 0) { |
109 | /* reuse the real, existing symbol */ |
110 | inline_sym = base_sym; |
111 | /* ensure that we don't alias an inlined symbol, which could |
112 | * lead to double frees in inline_node__delete |
113 | */ |
114 | assert(!base_sym->inlined); |
115 | } else { |
116 | /* create a fake symbol for the inline frame */ |
117 | inline_sym = symbol__new(start: base_sym ? base_sym->start : 0, |
118 | len: base_sym ? (base_sym->end - base_sym->start) : 0, |
119 | binding: base_sym ? base_sym->binding : 0, |
120 | type: base_sym ? base_sym->type : 0, |
121 | name: funcname); |
122 | if (inline_sym) |
123 | inline_sym->inlined = 1; |
124 | } |
125 | |
126 | free(demangled); |
127 | |
128 | return inline_sym; |
129 | } |
130 | |
131 | #define MAX_INLINE_NEST 1024 |
132 | |
133 | #ifdef HAVE_LIBBFD_SUPPORT |
134 | |
135 | /* |
136 | * Implement addr2line using libbfd. |
137 | */ |
138 | #define PACKAGE "perf" |
139 | #include <bfd.h> |
140 | |
141 | struct a2l_data { |
142 | const char *input; |
143 | u64 addr; |
144 | |
145 | bool found; |
146 | const char *filename; |
147 | const char *funcname; |
148 | unsigned line; |
149 | |
150 | bfd *abfd; |
151 | asymbol **syms; |
152 | }; |
153 | |
154 | static int bfd_error(const char *string) |
155 | { |
156 | const char *errmsg; |
157 | |
158 | errmsg = bfd_errmsg(bfd_get_error()); |
159 | fflush(stdout); |
160 | |
161 | if (string) |
162 | pr_debug("%s: %s\n" , string, errmsg); |
163 | else |
164 | pr_debug("%s\n" , errmsg); |
165 | |
166 | return -1; |
167 | } |
168 | |
169 | static int slurp_symtab(bfd *abfd, struct a2l_data *a2l) |
170 | { |
171 | long storage; |
172 | long symcount; |
173 | asymbol **syms; |
174 | bfd_boolean dynamic = FALSE; |
175 | |
176 | if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0) |
177 | return bfd_error(bfd_get_filename(abfd)); |
178 | |
179 | storage = bfd_get_symtab_upper_bound(abfd); |
180 | if (storage == 0L) { |
181 | storage = bfd_get_dynamic_symtab_upper_bound(abfd); |
182 | dynamic = TRUE; |
183 | } |
184 | if (storage < 0L) |
185 | return bfd_error(bfd_get_filename(abfd)); |
186 | |
187 | syms = malloc(storage); |
188 | if (dynamic) |
189 | symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); |
190 | else |
191 | symcount = bfd_canonicalize_symtab(abfd, syms); |
192 | |
193 | if (symcount < 0) { |
194 | free(syms); |
195 | return bfd_error(bfd_get_filename(abfd)); |
196 | } |
197 | |
198 | a2l->syms = syms; |
199 | return 0; |
200 | } |
201 | |
202 | static void find_address_in_section(bfd *abfd, asection *section, void *data) |
203 | { |
204 | bfd_vma pc, vma; |
205 | bfd_size_type size; |
206 | struct a2l_data *a2l = data; |
207 | flagword flags; |
208 | |
209 | if (a2l->found) |
210 | return; |
211 | |
212 | #ifdef bfd_get_section_flags |
213 | flags = bfd_get_section_flags(abfd, section); |
214 | #else |
215 | flags = bfd_section_flags(section); |
216 | #endif |
217 | if ((flags & SEC_ALLOC) == 0) |
218 | return; |
219 | |
220 | pc = a2l->addr; |
221 | #ifdef bfd_get_section_vma |
222 | vma = bfd_get_section_vma(abfd, section); |
223 | #else |
224 | vma = bfd_section_vma(section); |
225 | #endif |
226 | #ifdef bfd_get_section_size |
227 | size = bfd_get_section_size(section); |
228 | #else |
229 | size = bfd_section_size(section); |
230 | #endif |
231 | |
232 | if (pc < vma || pc >= vma + size) |
233 | return; |
234 | |
235 | a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma, |
236 | &a2l->filename, &a2l->funcname, |
237 | &a2l->line); |
238 | |
239 | if (a2l->filename && !strlen(a2l->filename)) |
240 | a2l->filename = NULL; |
241 | } |
242 | |
243 | static struct a2l_data *addr2line_init(const char *path) |
244 | { |
245 | bfd *abfd; |
246 | struct a2l_data *a2l = NULL; |
247 | |
248 | abfd = bfd_openr(path, NULL); |
249 | if (abfd == NULL) |
250 | return NULL; |
251 | |
252 | if (!bfd_check_format(abfd, bfd_object)) |
253 | goto out; |
254 | |
255 | a2l = zalloc(sizeof(*a2l)); |
256 | if (a2l == NULL) |
257 | goto out; |
258 | |
259 | a2l->abfd = abfd; |
260 | a2l->input = strdup(path); |
261 | if (a2l->input == NULL) |
262 | goto out; |
263 | |
264 | if (slurp_symtab(abfd, a2l)) |
265 | goto out; |
266 | |
267 | return a2l; |
268 | |
269 | out: |
270 | if (a2l) { |
271 | zfree((char **)&a2l->input); |
272 | free(a2l); |
273 | } |
274 | bfd_close(abfd); |
275 | return NULL; |
276 | } |
277 | |
278 | static void addr2line_cleanup(struct a2l_data *a2l) |
279 | { |
280 | if (a2l->abfd) |
281 | bfd_close(a2l->abfd); |
282 | zfree((char **)&a2l->input); |
283 | zfree(&a2l->syms); |
284 | free(a2l); |
285 | } |
286 | |
287 | static int inline_list__append_dso_a2l(struct dso *dso, |
288 | struct inline_node *node, |
289 | struct symbol *sym) |
290 | { |
291 | struct a2l_data *a2l = dso->a2l; |
292 | struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname); |
293 | char *srcline = NULL; |
294 | |
295 | if (a2l->filename) |
296 | srcline = srcline_from_fileline(a2l->filename, a2l->line); |
297 | |
298 | return inline_list__append(inline_sym, srcline, node); |
299 | } |
300 | |
301 | static int addr2line(const char *dso_name, u64 addr, |
302 | char **file, unsigned int *line, struct dso *dso, |
303 | bool unwind_inlines, struct inline_node *node, |
304 | struct symbol *sym) |
305 | { |
306 | int ret = 0; |
307 | struct a2l_data *a2l = dso->a2l; |
308 | |
309 | if (!a2l) { |
310 | dso->a2l = addr2line_init(dso_name); |
311 | a2l = dso->a2l; |
312 | } |
313 | |
314 | if (a2l == NULL) { |
315 | if (!symbol_conf.disable_add2line_warn) |
316 | pr_warning("addr2line_init failed for %s\n" , dso_name); |
317 | return 0; |
318 | } |
319 | |
320 | a2l->addr = addr; |
321 | a2l->found = false; |
322 | |
323 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); |
324 | |
325 | if (!a2l->found) |
326 | return 0; |
327 | |
328 | if (unwind_inlines) { |
329 | int cnt = 0; |
330 | |
331 | if (node && inline_list__append_dso_a2l(dso, node, sym)) |
332 | return 0; |
333 | |
334 | while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, |
335 | &a2l->funcname, &a2l->line) && |
336 | cnt++ < MAX_INLINE_NEST) { |
337 | |
338 | if (a2l->filename && !strlen(a2l->filename)) |
339 | a2l->filename = NULL; |
340 | |
341 | if (node != NULL) { |
342 | if (inline_list__append_dso_a2l(dso, node, sym)) |
343 | return 0; |
344 | // found at least one inline frame |
345 | ret = 1; |
346 | } |
347 | } |
348 | } |
349 | |
350 | if (file) { |
351 | *file = a2l->filename ? strdup(a2l->filename) : NULL; |
352 | ret = *file ? 1 : 0; |
353 | } |
354 | |
355 | if (line) |
356 | *line = a2l->line; |
357 | |
358 | return ret; |
359 | } |
360 | |
361 | void dso__free_a2l(struct dso *dso) |
362 | { |
363 | struct a2l_data *a2l = dso->a2l; |
364 | |
365 | if (!a2l) |
366 | return; |
367 | |
368 | addr2line_cleanup(a2l); |
369 | |
370 | dso->a2l = NULL; |
371 | } |
372 | |
373 | #else /* HAVE_LIBBFD_SUPPORT */ |
374 | |
375 | static int filename_split(char *filename, unsigned int *line_nr) |
376 | { |
377 | char *sep; |
378 | |
379 | sep = strchr(filename, '\n'); |
380 | if (sep) |
381 | *sep = '\0'; |
382 | |
383 | if (!strcmp(filename, "??:0" )) |
384 | return 0; |
385 | |
386 | sep = strchr(filename, ':'); |
387 | if (sep) { |
388 | *sep++ = '\0'; |
389 | *line_nr = strtoul(sep, NULL, 0); |
390 | return 1; |
391 | } |
392 | pr_debug("addr2line missing ':' in filename split\n" ); |
393 | return 0; |
394 | } |
395 | |
396 | static void addr2line_subprocess_cleanup(struct child_process *a2l) |
397 | { |
398 | if (a2l->pid != -1) { |
399 | kill(a2l->pid, SIGKILL); |
400 | finish_command(a2l); /* ignore result, we don't care */ |
401 | a2l->pid = -1; |
402 | close(a2l->in); |
403 | close(a2l->out); |
404 | } |
405 | |
406 | free(a2l); |
407 | } |
408 | |
409 | static struct child_process *addr2line_subprocess_init(const char *addr2line_path, |
410 | const char *binary_path) |
411 | { |
412 | const char *argv[] = { |
413 | addr2line_path ?: "addr2line" , |
414 | "-e" , binary_path, |
415 | "-a" , "-i" , "-f" , NULL |
416 | }; |
417 | struct child_process *a2l = zalloc(sizeof(*a2l)); |
418 | int start_command_status = 0; |
419 | |
420 | if (a2l == NULL) { |
421 | pr_err("Failed to allocate memory for addr2line" ); |
422 | return NULL; |
423 | } |
424 | |
425 | a2l->pid = -1; |
426 | a2l->in = -1; |
427 | a2l->out = -1; |
428 | a2l->no_stderr = 1; |
429 | |
430 | a2l->argv = argv; |
431 | start_command_status = start_command(a2l); |
432 | a2l->argv = NULL; /* it's not used after start_command; avoid dangling pointers */ |
433 | |
434 | if (start_command_status != 0) { |
435 | pr_warning("could not start addr2line (%s) for %s: start_command return code %d\n" , |
436 | addr2line_path, binary_path, start_command_status); |
437 | addr2line_subprocess_cleanup(a2l); |
438 | return NULL; |
439 | } |
440 | |
441 | return a2l; |
442 | } |
443 | |
444 | enum a2l_style { |
445 | BROKEN, |
446 | GNU_BINUTILS, |
447 | LLVM, |
448 | }; |
449 | |
450 | static enum a2l_style addr2line_configure(struct child_process *a2l, const char *dso_name) |
451 | { |
452 | static bool cached; |
453 | static enum a2l_style style; |
454 | |
455 | if (!cached) { |
456 | char buf[128]; |
457 | struct io io; |
458 | int ch; |
459 | int lines; |
460 | |
461 | if (write(a2l->in, ",\n" , 2) != 2) |
462 | return BROKEN; |
463 | |
464 | io__init(&io, a2l->out, buf, sizeof(buf)); |
465 | ch = io__get_char(&io); |
466 | if (ch == ',') { |
467 | style = LLVM; |
468 | cached = true; |
469 | lines = 1; |
470 | pr_debug("Detected LLVM addr2line style\n" ); |
471 | } else if (ch == '0') { |
472 | style = GNU_BINUTILS; |
473 | cached = true; |
474 | lines = 3; |
475 | pr_debug("Detected binutils addr2line style\n" ); |
476 | } else { |
477 | if (!symbol_conf.disable_add2line_warn) { |
478 | char *output = NULL; |
479 | size_t output_len; |
480 | |
481 | io__getline(&io, &output, &output_len); |
482 | pr_warning("%s %s: addr2line configuration failed\n" , |
483 | __func__, dso_name); |
484 | pr_warning("\t%c%s" , ch, output); |
485 | } |
486 | pr_debug("Unknown/broken addr2line style\n" ); |
487 | return BROKEN; |
488 | } |
489 | while (lines) { |
490 | ch = io__get_char(&io); |
491 | if (ch <= 0) |
492 | break; |
493 | if (ch == '\n') |
494 | lines--; |
495 | } |
496 | /* Ignore SIGPIPE in the event addr2line exits. */ |
497 | signal(SIGPIPE, SIG_IGN); |
498 | } |
499 | return style; |
500 | } |
501 | |
502 | static int read_addr2line_record(struct io *io, |
503 | enum a2l_style style, |
504 | const char *dso_name, |
505 | u64 addr, |
506 | bool first, |
507 | char **function, |
508 | char **filename, |
509 | unsigned int *line_nr) |
510 | { |
511 | /* |
512 | * Returns: |
513 | * -1 ==> error |
514 | * 0 ==> sentinel (or other ill-formed) record read |
515 | * 1 ==> a genuine record read |
516 | */ |
517 | char *line = NULL; |
518 | size_t line_len = 0; |
519 | unsigned int dummy_line_nr = 0; |
520 | int ret = -1; |
521 | |
522 | if (function != NULL) |
523 | zfree(function); |
524 | |
525 | if (filename != NULL) |
526 | zfree(filename); |
527 | |
528 | if (line_nr != NULL) |
529 | *line_nr = 0; |
530 | |
531 | /* |
532 | * Read the first line. Without an error this will be: |
533 | * - for the first line an address like 0x1234, |
534 | * - the binutils sentinel 0x0000000000000000, |
535 | * - the llvm-addr2line the sentinel ',' character, |
536 | * - the function name line for an inlined function. |
537 | */ |
538 | if (io__getline(io, &line, &line_len) < 0 || !line_len) |
539 | goto error; |
540 | |
541 | pr_debug("%s %s: addr2line read address for sentinel: %s" , __func__, dso_name, line); |
542 | if (style == LLVM && line_len == 2 && line[0] == ',') { |
543 | /* Found the llvm-addr2line sentinel character. */ |
544 | zfree(&line); |
545 | return 0; |
546 | } else if (style == GNU_BINUTILS && (!first || addr != 0)) { |
547 | int zero_count = 0, non_zero_count = 0; |
548 | /* |
549 | * Check for binutils sentinel ignoring it for the case the |
550 | * requested address is 0. |
551 | */ |
552 | |
553 | /* A given address should always start 0x. */ |
554 | if (line_len >= 2 || line[0] != '0' || line[1] != 'x') { |
555 | for (size_t i = 2; i < line_len; i++) { |
556 | if (line[i] == '0') |
557 | zero_count++; |
558 | else if (line[i] != '\n') |
559 | non_zero_count++; |
560 | } |
561 | if (!non_zero_count) { |
562 | int ch; |
563 | |
564 | if (first && !zero_count) { |
565 | /* Line was erroneous just '0x'. */ |
566 | goto error; |
567 | } |
568 | /* |
569 | * Line was 0x0..0, the sentinel for binutils. Remove |
570 | * the function and filename lines. |
571 | */ |
572 | zfree(&line); |
573 | do { |
574 | ch = io__get_char(io); |
575 | } while (ch > 0 && ch != '\n'); |
576 | do { |
577 | ch = io__get_char(io); |
578 | } while (ch > 0 && ch != '\n'); |
579 | return 0; |
580 | } |
581 | } |
582 | } |
583 | /* Read the second function name line (if inline data then this is the first line). */ |
584 | if (first && (io__getline(io, &line, &line_len) < 0 || !line_len)) |
585 | goto error; |
586 | |
587 | pr_debug("%s %s: addr2line read line: %s" , __func__, dso_name, line); |
588 | if (function != NULL) |
589 | *function = strdup(strim(line)); |
590 | |
591 | zfree(&line); |
592 | line_len = 0; |
593 | |
594 | /* Read the third filename and line number line. */ |
595 | if (io__getline(io, &line, &line_len) < 0 || !line_len) |
596 | goto error; |
597 | |
598 | pr_debug("%s %s: addr2line filename:number : %s" , __func__, dso_name, line); |
599 | if (filename_split(filename: line, line_nr: line_nr == NULL ? &dummy_line_nr : line_nr) == 0 && |
600 | style == GNU_BINUTILS) { |
601 | ret = 0; |
602 | goto error; |
603 | } |
604 | |
605 | if (filename != NULL) |
606 | *filename = strdup(line); |
607 | |
608 | zfree(&line); |
609 | line_len = 0; |
610 | |
611 | return 1; |
612 | |
613 | error: |
614 | free(line); |
615 | if (function != NULL) |
616 | zfree(function); |
617 | if (filename != NULL) |
618 | zfree(filename); |
619 | return ret; |
620 | } |
621 | |
622 | static int inline_list__append_record(struct dso *dso, |
623 | struct inline_node *node, |
624 | struct symbol *sym, |
625 | const char *function, |
626 | const char *filename, |
627 | unsigned int line_nr) |
628 | { |
629 | struct symbol *inline_sym = new_inline_sym(dso, base_sym: sym, funcname: function); |
630 | |
631 | return inline_list__append(symbol: inline_sym, srcline: srcline_from_fileline(file: filename, line: line_nr), node); |
632 | } |
633 | |
634 | static int addr2line(const char *dso_name, u64 addr, |
635 | char **file, unsigned int *line_nr, |
636 | struct dso *dso, |
637 | bool unwind_inlines, |
638 | struct inline_node *node, |
639 | struct symbol *sym __maybe_unused) |
640 | { |
641 | struct child_process *a2l = dso->a2l; |
642 | char *record_function = NULL; |
643 | char *record_filename = NULL; |
644 | unsigned int record_line_nr = 0; |
645 | int record_status = -1; |
646 | int ret = 0; |
647 | size_t inline_count = 0; |
648 | int len; |
649 | char buf[128]; |
650 | ssize_t written; |
651 | struct io io = { .eof = false }; |
652 | enum a2l_style a2l_style; |
653 | |
654 | if (!a2l) { |
655 | if (!filename__has_section(filename: dso_name, sec: ".debug_line" )) |
656 | goto out; |
657 | |
658 | dso->a2l = addr2line_subprocess_init(addr2line_path: symbol_conf.addr2line_path, binary_path: dso_name); |
659 | a2l = dso->a2l; |
660 | } |
661 | |
662 | if (a2l == NULL) { |
663 | if (!symbol_conf.disable_add2line_warn) |
664 | pr_warning("%s %s: addr2line_subprocess_init failed\n" , __func__, dso_name); |
665 | goto out; |
666 | } |
667 | a2l_style = addr2line_configure(a2l, dso_name); |
668 | if (a2l_style == BROKEN) |
669 | goto out; |
670 | |
671 | /* |
672 | * Send our request and then *deliberately* send something that can't be |
673 | * interpreted as a valid address to ask addr2line about (namely, |
674 | * ","). This causes addr2line to first write out the answer to our |
675 | * request, in an unbounded/unknown number of records, and then to write |
676 | * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or "," |
677 | * for llvm-addr2line, so that we can detect when it has finished giving |
678 | * us anything useful. |
679 | */ |
680 | len = snprintf(buf, sizeof(buf), "%016" PRIx64"\n,\n" , addr); |
681 | written = len > 0 ? write(a2l->in, buf, len) : -1; |
682 | if (written != len) { |
683 | if (!symbol_conf.disable_add2line_warn) |
684 | pr_warning("%s %s: could not send request\n" , __func__, dso_name); |
685 | goto out; |
686 | } |
687 | io__init(&io, a2l->out, buf, sizeof(buf)); |
688 | io.timeout_ms = addr2line_timeout_ms; |
689 | switch (read_addr2line_record(io: &io, style: a2l_style, dso_name, addr, /*first=*/true, |
690 | function: &record_function, filename: &record_filename, line_nr: &record_line_nr)) { |
691 | case -1: |
692 | if (!symbol_conf.disable_add2line_warn) |
693 | pr_warning("%s %s: could not read first record\n" , __func__, dso_name); |
694 | goto out; |
695 | case 0: |
696 | /* |
697 | * The first record was invalid, so return failure, but first |
698 | * read another record, since we sent a sentinel ',' for the |
699 | * sake of detected the last inlined function. Treat this as the |
700 | * first of a record as the ',' generates a new start with GNU |
701 | * binutils, also force a non-zero address as we're no longer |
702 | * reading that record. |
703 | */ |
704 | switch (read_addr2line_record(io: &io, style: a2l_style, dso_name, |
705 | /*addr=*/1, /*first=*/true, |
706 | NULL, NULL, NULL)) { |
707 | case -1: |
708 | if (!symbol_conf.disable_add2line_warn) |
709 | pr_warning("%s %s: could not read sentinel record\n" , |
710 | __func__, dso_name); |
711 | break; |
712 | case 0: |
713 | /* The sentinel as expected. */ |
714 | break; |
715 | default: |
716 | if (!symbol_conf.disable_add2line_warn) |
717 | pr_warning("%s %s: unexpected record instead of sentinel" , |
718 | __func__, dso_name); |
719 | break; |
720 | } |
721 | goto out; |
722 | default: |
723 | /* First record as expected. */ |
724 | break; |
725 | } |
726 | |
727 | if (file) { |
728 | *file = strdup(record_filename); |
729 | ret = 1; |
730 | } |
731 | if (line_nr) |
732 | *line_nr = record_line_nr; |
733 | |
734 | if (unwind_inlines) { |
735 | if (node && inline_list__append_record(dso, node, sym, |
736 | function: record_function, |
737 | filename: record_filename, |
738 | line_nr: record_line_nr)) { |
739 | ret = 0; |
740 | goto out; |
741 | } |
742 | } |
743 | |
744 | /* |
745 | * We have to read the records even if we don't care about the inline |
746 | * info. This isn't the first record and force the address to non-zero |
747 | * as we're reading records beyond the first. |
748 | */ |
749 | while ((record_status = read_addr2line_record(io: &io, |
750 | style: a2l_style, |
751 | dso_name, |
752 | /*addr=*/1, |
753 | /*first=*/false, |
754 | function: &record_function, |
755 | filename: &record_filename, |
756 | line_nr: &record_line_nr)) == 1) { |
757 | if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { |
758 | if (inline_list__append_record(dso, node, sym, |
759 | function: record_function, |
760 | filename: record_filename, |
761 | line_nr: record_line_nr)) { |
762 | ret = 0; |
763 | goto out; |
764 | } |
765 | ret = 1; /* found at least one inline frame */ |
766 | } |
767 | } |
768 | |
769 | out: |
770 | free(record_function); |
771 | free(record_filename); |
772 | if (io.eof) { |
773 | dso->a2l = NULL; |
774 | addr2line_subprocess_cleanup(a2l); |
775 | } |
776 | return ret; |
777 | } |
778 | |
779 | void dso__free_a2l(struct dso *dso) |
780 | { |
781 | struct child_process *a2l = dso->a2l; |
782 | |
783 | if (!a2l) |
784 | return; |
785 | |
786 | addr2line_subprocess_cleanup(a2l); |
787 | |
788 | dso->a2l = NULL; |
789 | } |
790 | |
791 | #endif /* HAVE_LIBBFD_SUPPORT */ |
792 | |
793 | static struct inline_node *addr2inlines(const char *dso_name, u64 addr, |
794 | struct dso *dso, struct symbol *sym) |
795 | { |
796 | struct inline_node *node; |
797 | |
798 | node = zalloc(sizeof(*node)); |
799 | if (node == NULL) { |
800 | perror("not enough memory for the inline node" ); |
801 | return NULL; |
802 | } |
803 | |
804 | INIT_LIST_HEAD(list: &node->val); |
805 | node->addr = addr; |
806 | |
807 | addr2line(dso_name, addr, NULL, NULL, dso, unwind_inlines: true, node, sym); |
808 | return node; |
809 | } |
810 | |
811 | /* |
812 | * Number of addr2line failures (without success) before disabling it for that |
813 | * dso. |
814 | */ |
815 | #define A2L_FAIL_LIMIT 123 |
816 | |
817 | char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, |
818 | bool show_sym, bool show_addr, bool unwind_inlines, |
819 | u64 ip) |
820 | { |
821 | char *file = NULL; |
822 | unsigned line = 0; |
823 | char *srcline; |
824 | const char *dso_name; |
825 | |
826 | if (!dso->has_srcline) |
827 | goto out; |
828 | |
829 | dso_name = dso__name(dso); |
830 | if (dso_name == NULL) |
831 | goto out; |
832 | |
833 | if (!addr2line(dso_name, addr, file: &file, line_nr: &line, dso, |
834 | unwind_inlines, NULL, sym)) |
835 | goto out; |
836 | |
837 | srcline = srcline_from_fileline(file, line); |
838 | free(file); |
839 | |
840 | if (!srcline) |
841 | goto out; |
842 | |
843 | dso->a2l_fails = 0; |
844 | |
845 | return srcline; |
846 | |
847 | out: |
848 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { |
849 | dso->has_srcline = 0; |
850 | dso__free_a2l(dso); |
851 | } |
852 | |
853 | if (!show_addr) |
854 | return (show_sym && sym) ? |
855 | strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN; |
856 | |
857 | if (sym) { |
858 | if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "" , |
859 | ip - sym->start) < 0) |
860 | return SRCLINE_UNKNOWN; |
861 | } else if (asprintf(&srcline, "%s[%" PRIx64 "]" , dso->short_name, addr) < 0) |
862 | return SRCLINE_UNKNOWN; |
863 | return srcline; |
864 | } |
865 | |
866 | /* Returns filename and fills in line number in line */ |
867 | char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line) |
868 | { |
869 | char *file = NULL; |
870 | const char *dso_name; |
871 | |
872 | if (!dso->has_srcline) |
873 | goto out; |
874 | |
875 | dso_name = dso__name(dso); |
876 | if (dso_name == NULL) |
877 | goto out; |
878 | |
879 | if (!addr2line(dso_name, addr, file: &file, line_nr: line, dso, unwind_inlines: true, NULL, NULL)) |
880 | goto out; |
881 | |
882 | dso->a2l_fails = 0; |
883 | return file; |
884 | |
885 | out: |
886 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { |
887 | dso->has_srcline = 0; |
888 | dso__free_a2l(dso); |
889 | } |
890 | |
891 | return NULL; |
892 | } |
893 | |
894 | void zfree_srcline(char **srcline) |
895 | { |
896 | if (*srcline == NULL) |
897 | return; |
898 | |
899 | if (*srcline != SRCLINE_UNKNOWN) |
900 | free(*srcline); |
901 | |
902 | *srcline = NULL; |
903 | } |
904 | |
905 | char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, |
906 | bool show_sym, bool show_addr, u64 ip) |
907 | { |
908 | return __get_srcline(dso, addr, sym, show_sym, show_addr, unwind_inlines: false, ip); |
909 | } |
910 | |
911 | struct srcline_node { |
912 | u64 addr; |
913 | char *srcline; |
914 | struct rb_node rb_node; |
915 | }; |
916 | |
917 | void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline) |
918 | { |
919 | struct rb_node **p = &tree->rb_root.rb_node; |
920 | struct rb_node *parent = NULL; |
921 | struct srcline_node *i, *node; |
922 | bool leftmost = true; |
923 | |
924 | node = zalloc(sizeof(struct srcline_node)); |
925 | if (!node) { |
926 | perror("not enough memory for the srcline node" ); |
927 | return; |
928 | } |
929 | |
930 | node->addr = addr; |
931 | node->srcline = srcline; |
932 | |
933 | while (*p != NULL) { |
934 | parent = *p; |
935 | i = rb_entry(parent, struct srcline_node, rb_node); |
936 | if (addr < i->addr) |
937 | p = &(*p)->rb_left; |
938 | else { |
939 | p = &(*p)->rb_right; |
940 | leftmost = false; |
941 | } |
942 | } |
943 | rb_link_node(node: &node->rb_node, parent, rb_link: p); |
944 | rb_insert_color_cached(node: &node->rb_node, root: tree, leftmost); |
945 | } |
946 | |
947 | char *srcline__tree_find(struct rb_root_cached *tree, u64 addr) |
948 | { |
949 | struct rb_node *n = tree->rb_root.rb_node; |
950 | |
951 | while (n) { |
952 | struct srcline_node *i = rb_entry(n, struct srcline_node, |
953 | rb_node); |
954 | |
955 | if (addr < i->addr) |
956 | n = n->rb_left; |
957 | else if (addr > i->addr) |
958 | n = n->rb_right; |
959 | else |
960 | return i->srcline; |
961 | } |
962 | |
963 | return NULL; |
964 | } |
965 | |
966 | void srcline__tree_delete(struct rb_root_cached *tree) |
967 | { |
968 | struct srcline_node *pos; |
969 | struct rb_node *next = rb_first_cached(tree); |
970 | |
971 | while (next) { |
972 | pos = rb_entry(next, struct srcline_node, rb_node); |
973 | next = rb_next(&pos->rb_node); |
974 | rb_erase_cached(node: &pos->rb_node, root: tree); |
975 | zfree_srcline(srcline: &pos->srcline); |
976 | zfree(&pos); |
977 | } |
978 | } |
979 | |
980 | struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr, |
981 | struct symbol *sym) |
982 | { |
983 | const char *dso_name; |
984 | |
985 | dso_name = dso__name(dso); |
986 | if (dso_name == NULL) |
987 | return NULL; |
988 | |
989 | return addr2inlines(dso_name, addr, dso, sym); |
990 | } |
991 | |
992 | void inline_node__delete(struct inline_node *node) |
993 | { |
994 | struct inline_list *ilist, *tmp; |
995 | |
996 | list_for_each_entry_safe(ilist, tmp, &node->val, list) { |
997 | list_del_init(entry: &ilist->list); |
998 | zfree_srcline(srcline: &ilist->srcline); |
999 | /* only the inlined symbols are owned by the list */ |
1000 | if (ilist->symbol && ilist->symbol->inlined) |
1001 | symbol__delete(sym: ilist->symbol); |
1002 | free(ilist); |
1003 | } |
1004 | |
1005 | free(node); |
1006 | } |
1007 | |
1008 | void inlines__tree_insert(struct rb_root_cached *tree, |
1009 | struct inline_node *inlines) |
1010 | { |
1011 | struct rb_node **p = &tree->rb_root.rb_node; |
1012 | struct rb_node *parent = NULL; |
1013 | const u64 addr = inlines->addr; |
1014 | struct inline_node *i; |
1015 | bool leftmost = true; |
1016 | |
1017 | while (*p != NULL) { |
1018 | parent = *p; |
1019 | i = rb_entry(parent, struct inline_node, rb_node); |
1020 | if (addr < i->addr) |
1021 | p = &(*p)->rb_left; |
1022 | else { |
1023 | p = &(*p)->rb_right; |
1024 | leftmost = false; |
1025 | } |
1026 | } |
1027 | rb_link_node(node: &inlines->rb_node, parent, rb_link: p); |
1028 | rb_insert_color_cached(node: &inlines->rb_node, root: tree, leftmost); |
1029 | } |
1030 | |
1031 | struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr) |
1032 | { |
1033 | struct rb_node *n = tree->rb_root.rb_node; |
1034 | |
1035 | while (n) { |
1036 | struct inline_node *i = rb_entry(n, struct inline_node, |
1037 | rb_node); |
1038 | |
1039 | if (addr < i->addr) |
1040 | n = n->rb_left; |
1041 | else if (addr > i->addr) |
1042 | n = n->rb_right; |
1043 | else |
1044 | return i; |
1045 | } |
1046 | |
1047 | return NULL; |
1048 | } |
1049 | |
1050 | void inlines__tree_delete(struct rb_root_cached *tree) |
1051 | { |
1052 | struct inline_node *pos; |
1053 | struct rb_node *next = rb_first_cached(tree); |
1054 | |
1055 | while (next) { |
1056 | pos = rb_entry(next, struct inline_node, rb_node); |
1057 | next = rb_next(&pos->rb_node); |
1058 | rb_erase_cached(node: &pos->rb_node, root: tree); |
1059 | inline_node__delete(node: pos); |
1060 | } |
1061 | } |
1062 | |