]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
fd20e811 | 2 | #include <inttypes.h> |
be8ecc57 | 3 | #include <signal.h> |
f048d548 NK |
4 | #include <stdio.h> |
5 | #include <stdlib.h> | |
6 | #include <string.h> | |
be8ecc57 | 7 | #include <sys/types.h> |
f048d548 NK |
8 | |
9 | #include <linux/kernel.h> | |
13c230ab | 10 | #include <linux/string.h> |
7f7c536f | 11 | #include <linux/zalloc.h> |
f048d548 | 12 | |
86c98cab | 13 | #include "util/dso.h" |
f048d548 | 14 | #include "util/debug.h" |
a64489c5 | 15 | #include "util/callchain.h" |
b10c78c5 | 16 | #include "util/symbol_conf.h" |
632a5cab | 17 | #include "srcline.h" |
7285cf33 | 18 | #include "string2.h" |
85c116a6 | 19 | #include "symbol.h" |
be8ecc57 | 20 | #include "subcmd/run-command.h" |
85c116a6 | 21 | |
a9710ba0 AK |
22 | bool srcline_full_filename; |
23 | ||
5580338d JY |
24 | static const char *dso__name(struct dso *dso) |
25 | { | |
26 | const char *dso_name; | |
27 | ||
28 | if (dso->symsrc_filename) | |
29 | dso_name = dso->symsrc_filename; | |
30 | else | |
31 | dso_name = dso->long_name; | |
32 | ||
33 | if (dso_name[0] == '[') | |
34 | return NULL; | |
35 | ||
36 | if (!strncmp(dso_name, "/tmp/perf-", 10)) | |
37 | return NULL; | |
38 | ||
39 | return dso_name; | |
40 | } | |
41 | ||
2be8832f MW |
42 | static int inline_list__append(struct symbol *symbol, char *srcline, |
43 | struct inline_node *node) | |
a64489c5 JY |
44 | { |
45 | struct inline_list *ilist; | |
a64489c5 JY |
46 | |
47 | ilist = zalloc(sizeof(*ilist)); | |
48 | if (ilist == NULL) | |
49 | return -1; | |
50 | ||
fea0cf84 | 51 | ilist->symbol = symbol; |
2be8832f | 52 | ilist->srcline = srcline; |
a64489c5 | 53 | |
28071f51 MW |
54 | if (callchain_param.order == ORDER_CALLEE) |
55 | list_add_tail(&ilist->list, &node->val); | |
56 | else | |
57 | list_add(&ilist->list, &node->val); | |
a64489c5 JY |
58 | |
59 | return 0; | |
60 | } | |
61 | ||
2be8832f MW |
62 | /* basename version that takes a const input string */ |
63 | static const char *gnu_basename(const char *path) | |
64 | { | |
65 | const char *base = strrchr(path, '/'); | |
66 | ||
67 | return base ? base + 1 : path; | |
68 | } | |
69 | ||
70 | static char *srcline_from_fileline(const char *file, unsigned int line) | |
71 | { | |
72 | char *srcline; | |
73 | ||
74 | if (!file) | |
75 | return NULL; | |
76 | ||
77 | if (!srcline_full_filename) | |
78 | file = gnu_basename(file); | |
79 | ||
80 | if (asprintf(&srcline, "%s:%u", file, line) < 0) | |
81 | return NULL; | |
82 | ||
83 | return srcline; | |
84 | } | |
85 | ||
7285cf33 NK |
86 | static struct symbol *new_inline_sym(struct dso *dso, |
87 | struct symbol *base_sym, | |
88 | const char *funcname) | |
89 | { | |
90 | struct symbol *inline_sym; | |
91 | char *demangled = NULL; | |
92 | ||
d4046e8e MW |
93 | if (!funcname) |
94 | funcname = "??"; | |
95 | ||
7285cf33 NK |
96 | if (dso) { |
97 | demangled = dso__demangle_sym(dso, 0, funcname); | |
98 | if (demangled) | |
99 | funcname = demangled; | |
100 | } | |
101 | ||
102 | if (base_sym && strcmp(funcname, base_sym->name) == 0) { | |
103 | /* reuse the real, existing symbol */ | |
104 | inline_sym = base_sym; | |
105 | /* ensure that we don't alias an inlined symbol, which could | |
106 | * lead to double frees in inline_node__delete | |
107 | */ | |
108 | assert(!base_sym->inlined); | |
109 | } else { | |
110 | /* create a fake symbol for the inline frame */ | |
111 | inline_sym = symbol__new(base_sym ? base_sym->start : 0, | |
7346195e | 112 | base_sym ? (base_sym->end - base_sym->start) : 0, |
7285cf33 | 113 | base_sym ? base_sym->binding : 0, |
af30bffa | 114 | base_sym ? base_sym->type : 0, |
7285cf33 NK |
115 | funcname); |
116 | if (inline_sym) | |
117 | inline_sym->inlined = 1; | |
118 | } | |
119 | ||
120 | free(demangled); | |
121 | ||
122 | return inline_sym; | |
123 | } | |
124 | ||
be8ecc57 TGJ |
125 | #define MAX_INLINE_NEST 1024 |
126 | ||
2f48fcd8 RV |
127 | #ifdef HAVE_LIBBFD_SUPPORT |
128 | ||
129 | /* | |
130 | * Implement addr2line using libbfd. | |
131 | */ | |
132 | #define PACKAGE "perf" | |
133 | #include <bfd.h> | |
134 | ||
135 | struct a2l_data { | |
136 | const char *input; | |
ac931f87 | 137 | u64 addr; |
2f48fcd8 RV |
138 | |
139 | bool found; | |
140 | const char *filename; | |
141 | const char *funcname; | |
142 | unsigned line; | |
143 | ||
144 | bfd *abfd; | |
145 | asymbol **syms; | |
146 | }; | |
147 | ||
148 | static int bfd_error(const char *string) | |
149 | { | |
150 | const char *errmsg; | |
151 | ||
152 | errmsg = bfd_errmsg(bfd_get_error()); | |
153 | fflush(stdout); | |
154 | ||
155 | if (string) | |
156 | pr_debug("%s: %s\n", string, errmsg); | |
157 | else | |
158 | pr_debug("%s\n", errmsg); | |
159 | ||
160 | return -1; | |
161 | } | |
162 | ||
163 | static int slurp_symtab(bfd *abfd, struct a2l_data *a2l) | |
164 | { | |
165 | long storage; | |
166 | long symcount; | |
167 | asymbol **syms; | |
168 | bfd_boolean dynamic = FALSE; | |
169 | ||
170 | if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0) | |
171 | return bfd_error(bfd_get_filename(abfd)); | |
172 | ||
173 | storage = bfd_get_symtab_upper_bound(abfd); | |
174 | if (storage == 0L) { | |
175 | storage = bfd_get_dynamic_symtab_upper_bound(abfd); | |
176 | dynamic = TRUE; | |
177 | } | |
178 | if (storage < 0L) | |
179 | return bfd_error(bfd_get_filename(abfd)); | |
180 | ||
181 | syms = malloc(storage); | |
182 | if (dynamic) | |
183 | symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); | |
184 | else | |
185 | symcount = bfd_canonicalize_symtab(abfd, syms); | |
186 | ||
187 | if (symcount < 0) { | |
188 | free(syms); | |
189 | return bfd_error(bfd_get_filename(abfd)); | |
190 | } | |
191 | ||
192 | a2l->syms = syms; | |
193 | return 0; | |
194 | } | |
195 | ||
196 | static void find_address_in_section(bfd *abfd, asection *section, void *data) | |
197 | { | |
198 | bfd_vma pc, vma; | |
199 | bfd_size_type size; | |
200 | struct a2l_data *a2l = data; | |
0ada120c | 201 | flagword flags; |
2f48fcd8 RV |
202 | |
203 | if (a2l->found) | |
204 | return; | |
205 | ||
0ada120c CD |
206 | #ifdef bfd_get_section_flags |
207 | flags = bfd_get_section_flags(abfd, section); | |
208 | #else | |
209 | flags = bfd_section_flags(section); | |
210 | #endif | |
211 | if ((flags & SEC_ALLOC) == 0) | |
2f48fcd8 RV |
212 | return; |
213 | ||
214 | pc = a2l->addr; | |
0ada120c | 215 | #ifdef bfd_get_section_vma |
2f48fcd8 | 216 | vma = bfd_get_section_vma(abfd, section); |
0ada120c CD |
217 | #else |
218 | vma = bfd_section_vma(section); | |
219 | #endif | |
220 | #ifdef bfd_get_section_size | |
2f48fcd8 | 221 | size = bfd_get_section_size(section); |
0ada120c CD |
222 | #else |
223 | size = bfd_section_size(section); | |
224 | #endif | |
2f48fcd8 RV |
225 | |
226 | if (pc < vma || pc >= vma + size) | |
227 | return; | |
228 | ||
229 | a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma, | |
230 | &a2l->filename, &a2l->funcname, | |
231 | &a2l->line); | |
d964b1cd MW |
232 | |
233 | if (a2l->filename && !strlen(a2l->filename)) | |
234 | a2l->filename = NULL; | |
2f48fcd8 RV |
235 | } |
236 | ||
237 | static struct a2l_data *addr2line_init(const char *path) | |
238 | { | |
239 | bfd *abfd; | |
240 | struct a2l_data *a2l = NULL; | |
241 | ||
242 | abfd = bfd_openr(path, NULL); | |
243 | if (abfd == NULL) | |
244 | return NULL; | |
245 | ||
246 | if (!bfd_check_format(abfd, bfd_object)) | |
247 | goto out; | |
248 | ||
249 | a2l = zalloc(sizeof(*a2l)); | |
250 | if (a2l == NULL) | |
251 | goto out; | |
252 | ||
253 | a2l->abfd = abfd; | |
254 | a2l->input = strdup(path); | |
255 | if (a2l->input == NULL) | |
256 | goto out; | |
257 | ||
258 | if (slurp_symtab(abfd, a2l)) | |
259 | goto out; | |
260 | ||
261 | return a2l; | |
262 | ||
263 | out: | |
264 | if (a2l) { | |
7d16c634 | 265 | zfree((char **)&a2l->input); |
2f48fcd8 RV |
266 | free(a2l); |
267 | } | |
268 | bfd_close(abfd); | |
269 | return NULL; | |
270 | } | |
271 | ||
272 | static void addr2line_cleanup(struct a2l_data *a2l) | |
273 | { | |
274 | if (a2l->abfd) | |
275 | bfd_close(a2l->abfd); | |
7d16c634 | 276 | zfree((char **)&a2l->input); |
74cf249d | 277 | zfree(&a2l->syms); |
2f48fcd8 RV |
278 | free(a2l); |
279 | } | |
280 | ||
4d53b9d5 | 281 | static int inline_list__append_dso_a2l(struct dso *dso, |
fea0cf84 MW |
282 | struct inline_node *node, |
283 | struct symbol *sym) | |
4d53b9d5 MW |
284 | { |
285 | struct a2l_data *a2l = dso->a2l; | |
fea0cf84 | 286 | struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname); |
2be8832f | 287 | char *srcline = NULL; |
4d53b9d5 | 288 | |
2be8832f MW |
289 | if (a2l->filename) |
290 | srcline = srcline_from_fileline(a2l->filename, a2l->line); | |
291 | ||
292 | return inline_list__append(inline_sym, srcline, node); | |
4d53b9d5 MW |
293 | } |
294 | ||
ac931f87 | 295 | static int addr2line(const char *dso_name, u64 addr, |
2f84b42b | 296 | char **file, unsigned int *line, struct dso *dso, |
fea0cf84 MW |
297 | bool unwind_inlines, struct inline_node *node, |
298 | struct symbol *sym) | |
2f48fcd8 RV |
299 | { |
300 | int ret = 0; | |
454ff00f AH |
301 | struct a2l_data *a2l = dso->a2l; |
302 | ||
303 | if (!a2l) { | |
304 | dso->a2l = addr2line_init(dso_name); | |
305 | a2l = dso->a2l; | |
306 | } | |
2f48fcd8 | 307 | |
2f48fcd8 | 308 | if (a2l == NULL) { |
b10c78c5 JY |
309 | if (!symbol_conf.disable_add2line_warn) |
310 | pr_warning("addr2line_init failed for %s\n", dso_name); | |
2f48fcd8 RV |
311 | return 0; |
312 | } | |
313 | ||
314 | a2l->addr = addr; | |
454ff00f AH |
315 | a2l->found = false; |
316 | ||
2f48fcd8 RV |
317 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); |
318 | ||
b21cc978 MW |
319 | if (!a2l->found) |
320 | return 0; | |
321 | ||
322 | if (unwind_inlines) { | |
2f84b42b AK |
323 | int cnt = 0; |
324 | ||
fea0cf84 | 325 | if (node && inline_list__append_dso_a2l(dso, node, sym)) |
4d53b9d5 MW |
326 | return 0; |
327 | ||
2f84b42b AK |
328 | while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, |
329 | &a2l->funcname, &a2l->line) && | |
a64489c5 JY |
330 | cnt++ < MAX_INLINE_NEST) { |
331 | ||
d964b1cd MW |
332 | if (a2l->filename && !strlen(a2l->filename)) |
333 | a2l->filename = NULL; | |
334 | ||
a64489c5 | 335 | if (node != NULL) { |
fea0cf84 | 336 | if (inline_list__append_dso_a2l(dso, node, sym)) |
a64489c5 | 337 | return 0; |
b21cc978 MW |
338 | // found at least one inline frame |
339 | ret = 1; | |
a64489c5 JY |
340 | } |
341 | } | |
2f84b42b AK |
342 | } |
343 | ||
b21cc978 MW |
344 | if (file) { |
345 | *file = a2l->filename ? strdup(a2l->filename) : NULL; | |
346 | ret = *file ? 1 : 0; | |
2f48fcd8 RV |
347 | } |
348 | ||
b21cc978 MW |
349 | if (line) |
350 | *line = a2l->line; | |
351 | ||
2f48fcd8 RV |
352 | return ret; |
353 | } | |
354 | ||
454ff00f AH |
355 | void dso__free_a2l(struct dso *dso) |
356 | { | |
357 | struct a2l_data *a2l = dso->a2l; | |
358 | ||
359 | if (!a2l) | |
360 | return; | |
361 | ||
362 | addr2line_cleanup(a2l); | |
363 | ||
364 | dso->a2l = NULL; | |
365 | } | |
366 | ||
2f48fcd8 RV |
367 | #else /* HAVE_LIBBFD_SUPPORT */ |
368 | ||
be8ecc57 TGJ |
369 | struct a2l_subprocess { |
370 | struct child_process addr2line; | |
371 | FILE *to_child; | |
372 | FILE *from_child; | |
373 | }; | |
374 | ||
5580338d JY |
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 | ||
393 | return 0; | |
394 | } | |
395 | ||
be8ecc57 | 396 | static void addr2line_subprocess_cleanup(struct a2l_subprocess *a2l) |
f048d548 | 397 | { |
be8ecc57 TGJ |
398 | if (a2l->addr2line.pid != -1) { |
399 | kill(a2l->addr2line.pid, SIGKILL); | |
400 | finish_command(&a2l->addr2line); /* ignore result, we don't care */ | |
401 | a2l->addr2line.pid = -1; | |
402 | } | |
f048d548 | 403 | |
be8ecc57 TGJ |
404 | if (a2l->to_child != NULL) { |
405 | fclose(a2l->to_child); | |
406 | a2l->to_child = NULL; | |
407 | } | |
f048d548 | 408 | |
be8ecc57 TGJ |
409 | if (a2l->from_child != NULL) { |
410 | fclose(a2l->from_child); | |
411 | a2l->from_child = NULL; | |
412 | } | |
413 | ||
414 | free(a2l); | |
415 | } | |
416 | ||
417 | static struct a2l_subprocess *addr2line_subprocess_init(const char *path) | |
418 | { | |
419 | const char *argv[] = { "addr2line", "-e", path, "-i", "-f", NULL }; | |
420 | struct a2l_subprocess *a2l = zalloc(sizeof(*a2l)); | |
421 | int start_command_status = 0; | |
422 | ||
423 | if (a2l == NULL) | |
424 | goto out; | |
425 | ||
426 | a2l->to_child = NULL; | |
427 | a2l->from_child = NULL; | |
428 | ||
429 | a2l->addr2line.pid = -1; | |
430 | a2l->addr2line.in = -1; | |
431 | a2l->addr2line.out = -1; | |
432 | a2l->addr2line.no_stderr = 1; | |
433 | ||
434 | a2l->addr2line.argv = argv; | |
435 | start_command_status = start_command(&a2l->addr2line); | |
436 | a2l->addr2line.argv = NULL; /* it's not used after start_command; avoid dangling pointers */ | |
437 | ||
438 | if (start_command_status != 0) { | |
439 | pr_warning("could not start addr2line for %s: start_command return code %d\n", | |
440 | path, | |
441 | start_command_status); | |
442 | goto out; | |
f048d548 NK |
443 | } |
444 | ||
be8ecc57 TGJ |
445 | a2l->to_child = fdopen(a2l->addr2line.in, "w"); |
446 | if (a2l->to_child == NULL) { | |
447 | pr_warning("could not open write-stream to addr2line of %s\n", path); | |
f048d548 NK |
448 | goto out; |
449 | } | |
450 | ||
be8ecc57 TGJ |
451 | a2l->from_child = fdopen(a2l->addr2line.out, "r"); |
452 | if (a2l->from_child == NULL) { | |
453 | pr_warning("could not open read-stream from addr2line of %s\n", path); | |
f048d548 NK |
454 | goto out; |
455 | } | |
456 | ||
be8ecc57 | 457 | return a2l; |
5580338d | 458 | |
f048d548 | 459 | out: |
be8ecc57 TGJ |
460 | if (a2l) |
461 | addr2line_subprocess_cleanup(a2l); | |
462 | ||
463 | return NULL; | |
f048d548 | 464 | } |
454ff00f | 465 | |
be8ecc57 TGJ |
466 | static int read_addr2line_record(struct a2l_subprocess *a2l, |
467 | char **function, | |
468 | char **filename, | |
469 | unsigned int *line_nr) | |
454ff00f | 470 | { |
be8ecc57 TGJ |
471 | /* |
472 | * Returns: | |
473 | * -1 ==> error | |
474 | * 0 ==> sentinel (or other ill-formed) record read | |
475 | * 1 ==> a genuine record read | |
476 | */ | |
477 | char *line = NULL; | |
478 | size_t line_len = 0; | |
479 | unsigned int dummy_line_nr = 0; | |
480 | int ret = -1; | |
481 | ||
482 | if (function != NULL) | |
483 | zfree(function); | |
484 | ||
485 | if (filename != NULL) | |
486 | zfree(filename); | |
487 | ||
488 | if (line_nr != NULL) | |
489 | *line_nr = 0; | |
490 | ||
491 | if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len) | |
492 | goto error; | |
493 | ||
494 | if (function != NULL) | |
495 | *function = strdup(strim(line)); | |
496 | ||
497 | zfree(&line); | |
498 | line_len = 0; | |
499 | ||
500 | if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len) | |
501 | goto error; | |
502 | ||
503 | if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0) { | |
504 | ret = 0; | |
505 | goto error; | |
506 | } | |
507 | ||
508 | if (filename != NULL) | |
509 | *filename = strdup(line); | |
510 | ||
511 | zfree(&line); | |
512 | line_len = 0; | |
513 | ||
514 | return 1; | |
515 | ||
516 | error: | |
517 | free(line); | |
518 | if (function != NULL) | |
519 | zfree(function); | |
520 | if (filename != NULL) | |
521 | zfree(filename); | |
522 | return ret; | |
454ff00f AH |
523 | } |
524 | ||
be8ecc57 TGJ |
525 | static int inline_list__append_record(struct dso *dso, |
526 | struct inline_node *node, | |
527 | struct symbol *sym, | |
528 | const char *function, | |
529 | const char *filename, | |
530 | unsigned int line_nr) | |
a64489c5 | 531 | { |
be8ecc57 | 532 | struct symbol *inline_sym = new_inline_sym(dso, sym, function); |
a64489c5 | 533 | |
be8ecc57 TGJ |
534 | return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node); |
535 | } | |
a64489c5 | 536 | |
be8ecc57 TGJ |
537 | static int addr2line(const char *dso_name, u64 addr, |
538 | char **file, unsigned int *line_nr, | |
539 | struct dso *dso, | |
540 | bool unwind_inlines, | |
541 | struct inline_node *node, | |
542 | struct symbol *sym __maybe_unused) | |
543 | { | |
544 | struct a2l_subprocess *a2l = dso->a2l; | |
545 | char *record_function = NULL; | |
546 | char *record_filename = NULL; | |
547 | unsigned int record_line_nr = 0; | |
548 | int record_status = -1; | |
549 | int ret = 0; | |
550 | size_t inline_count = 0; | |
551 | ||
552 | if (!a2l) { | |
553 | dso->a2l = addr2line_subprocess_init(dso_name); | |
554 | a2l = dso->a2l; | |
a64489c5 JY |
555 | } |
556 | ||
be8ecc57 TGJ |
557 | if (a2l == NULL) { |
558 | if (!symbol_conf.disable_add2line_warn) | |
559 | pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name); | |
a64489c5 JY |
560 | goto out; |
561 | } | |
562 | ||
be8ecc57 TGJ |
563 | /* |
564 | * Send our request and then *deliberately* send something that can't be interpreted as | |
565 | * a valid address to ask addr2line about (namely, ","). This causes addr2line to first | |
566 | * write out the answer to our request, in an unbounded/unknown number of records, and | |
567 | * then to write out the lines "??" and "??:0", so that we can detect when it has | |
568 | * finished giving us anything useful. We have to be careful about the first record, | |
569 | * though, because it may be genuinely unknown, in which case we'll get two sets of | |
570 | * "??"/"??:0" lines. | |
571 | */ | |
572 | if (fprintf(a2l->to_child, "%016"PRIx64"\n,\n", addr) < 0 || fflush(a2l->to_child) != 0) { | |
573 | pr_warning("%s %s: could not send request\n", __func__, dso_name); | |
574 | goto out; | |
575 | } | |
7285cf33 | 576 | |
be8ecc57 TGJ |
577 | switch (read_addr2line_record(a2l, &record_function, &record_filename, &record_line_nr)) { |
578 | case -1: | |
579 | pr_warning("%s %s: could not read first record\n", __func__, dso_name); | |
580 | goto out; | |
581 | case 0: | |
582 | /* | |
583 | * The first record was invalid, so return failure, but first read another | |
584 | * record, since we asked a junk question and have to clear the answer out. | |
585 | */ | |
586 | switch (read_addr2line_record(a2l, NULL, NULL, NULL)) { | |
587 | case -1: | |
588 | pr_warning("%s %s: could not read delimiter record\n", __func__, dso_name); | |
589 | break; | |
590 | case 0: | |
591 | /* As expected. */ | |
592 | break; | |
593 | default: | |
594 | pr_warning("%s %s: unexpected record instead of sentinel", | |
595 | __func__, dso_name); | |
596 | break; | |
597 | } | |
598 | goto out; | |
599 | default: | |
600 | break; | |
601 | } | |
7285cf33 | 602 | |
be8ecc57 TGJ |
603 | if (file) { |
604 | *file = strdup(record_filename); | |
605 | ret = 1; | |
606 | } | |
607 | if (line_nr) | |
608 | *line_nr = record_line_nr; | |
fea0cf84 | 609 | |
be8ecc57 TGJ |
610 | if (unwind_inlines) { |
611 | if (node && inline_list__append_record(dso, node, sym, | |
612 | record_function, | |
613 | record_filename, | |
614 | record_line_nr)) { | |
615 | ret = 0; | |
a64489c5 | 616 | goto out; |
be8ecc57 TGJ |
617 | } |
618 | } | |
a64489c5 | 619 | |
be8ecc57 TGJ |
620 | /* We have to read the records even if we don't care about the inline info. */ |
621 | while ((record_status = read_addr2line_record(a2l, | |
622 | &record_function, | |
623 | &record_filename, | |
624 | &record_line_nr)) == 1) { | |
625 | if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { | |
626 | if (inline_list__append_record(dso, node, sym, | |
627 | record_function, | |
628 | record_filename, | |
629 | record_line_nr)) { | |
630 | ret = 0; | |
631 | goto out; | |
632 | } | |
633 | ret = 1; /* found at least one inline frame */ | |
7285cf33 | 634 | } |
a64489c5 JY |
635 | } |
636 | ||
637 | out: | |
be8ecc57 TGJ |
638 | free(record_function); |
639 | free(record_filename); | |
640 | return ret; | |
641 | } | |
a64489c5 | 642 | |
be8ecc57 TGJ |
643 | void dso__free_a2l(struct dso *dso) |
644 | { | |
645 | struct a2l_subprocess *a2l = dso->a2l; | |
646 | ||
647 | if (!a2l) | |
648 | return; | |
649 | ||
650 | addr2line_subprocess_cleanup(a2l); | |
651 | ||
652 | dso->a2l = NULL; | |
a64489c5 JY |
653 | } |
654 | ||
2f48fcd8 | 655 | #endif /* HAVE_LIBBFD_SUPPORT */ |
f048d548 | 656 | |
be8ecc57 TGJ |
657 | static struct inline_node *addr2inlines(const char *dso_name, u64 addr, |
658 | struct dso *dso, struct symbol *sym) | |
659 | { | |
660 | struct inline_node *node; | |
661 | ||
662 | node = zalloc(sizeof(*node)); | |
663 | if (node == NULL) { | |
664 | perror("not enough memory for the inline node"); | |
665 | return NULL; | |
666 | } | |
667 | ||
668 | INIT_LIST_HEAD(&node->val); | |
669 | node->addr = addr; | |
670 | ||
671 | addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); | |
672 | return node; | |
673 | } | |
674 | ||
906049c8 AH |
675 | /* |
676 | * Number of addr2line failures (without success) before disabling it for that | |
677 | * dso. | |
678 | */ | |
679 | #define A2L_FAIL_LIMIT 123 | |
680 | ||
2f84b42b | 681 | char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, |
935f5a9d JY |
682 | bool show_sym, bool show_addr, bool unwind_inlines, |
683 | u64 ip) | |
f048d548 | 684 | { |
a949fffb DA |
685 | char *file = NULL; |
686 | unsigned line = 0; | |
2cc9d0ef | 687 | char *srcline; |
bf4414ae | 688 | const char *dso_name; |
f048d548 | 689 | |
2cc9d0ef | 690 | if (!dso->has_srcline) |
23f0981b | 691 | goto out; |
2cc9d0ef | 692 | |
5580338d JY |
693 | dso_name = dso__name(dso); |
694 | if (dso_name == NULL) | |
58d91a00 NK |
695 | goto out; |
696 | ||
fea0cf84 MW |
697 | if (!addr2line(dso_name, addr, &file, &line, dso, |
698 | unwind_inlines, NULL, sym)) | |
58d91a00 | 699 | goto out; |
f048d548 | 700 | |
2be8832f MW |
701 | srcline = srcline_from_fileline(file, line); |
702 | free(file); | |
703 | ||
704 | if (!srcline) | |
906049c8 | 705 | goto out; |
906049c8 AH |
706 | |
707 | dso->a2l_fails = 0; | |
f048d548 | 708 | |
f048d548 | 709 | return srcline; |
2cc9d0ef NK |
710 | |
711 | out: | |
906049c8 AH |
712 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { |
713 | dso->has_srcline = 0; | |
714 | dso__free_a2l(dso); | |
715 | } | |
5dfa210e MW |
716 | |
717 | if (!show_addr) | |
718 | return (show_sym && sym) ? | |
719 | strndup(sym->name, sym->namelen) : NULL; | |
720 | ||
85c116a6 | 721 | if (sym) { |
ac931f87 | 722 | if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", |
935f5a9d | 723 | ip - sym->start) < 0) |
85c116a6 | 724 | return SRCLINE_UNKNOWN; |
ac931f87 | 725 | } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0) |
23f0981b AK |
726 | return SRCLINE_UNKNOWN; |
727 | return srcline; | |
f048d548 NK |
728 | } |
729 | ||
dd2e18e9 AK |
730 | /* Returns filename and fills in line number in line */ |
731 | char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line) | |
732 | { | |
733 | char *file = NULL; | |
734 | const char *dso_name; | |
735 | ||
736 | if (!dso->has_srcline) | |
737 | goto out; | |
738 | ||
739 | dso_name = dso__name(dso); | |
740 | if (dso_name == NULL) | |
741 | goto out; | |
742 | ||
743 | if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL)) | |
744 | goto out; | |
745 | ||
746 | dso->a2l_fails = 0; | |
747 | return file; | |
748 | ||
749 | out: | |
750 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { | |
751 | dso->has_srcline = 0; | |
752 | dso__free_a2l(dso); | |
753 | } | |
754 | ||
755 | return NULL; | |
756 | } | |
757 | ||
f048d548 NK |
758 | void free_srcline(char *srcline) |
759 | { | |
760 | if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0) | |
761 | free(srcline); | |
762 | } | |
2f84b42b AK |
763 | |
764 | char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, | |
935f5a9d | 765 | bool show_sym, bool show_addr, u64 ip) |
2f84b42b | 766 | { |
935f5a9d | 767 | return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip); |
2f84b42b | 768 | } |
a64489c5 | 769 | |
21ac9d54 MW |
770 | struct srcline_node { |
771 | u64 addr; | |
772 | char *srcline; | |
773 | struct rb_node rb_node; | |
774 | }; | |
775 | ||
55ecd631 | 776 | void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline) |
21ac9d54 | 777 | { |
55ecd631 | 778 | struct rb_node **p = &tree->rb_root.rb_node; |
21ac9d54 MW |
779 | struct rb_node *parent = NULL; |
780 | struct srcline_node *i, *node; | |
55ecd631 | 781 | bool leftmost = true; |
21ac9d54 MW |
782 | |
783 | node = zalloc(sizeof(struct srcline_node)); | |
784 | if (!node) { | |
785 | perror("not enough memory for the srcline node"); | |
786 | return; | |
787 | } | |
788 | ||
789 | node->addr = addr; | |
790 | node->srcline = srcline; | |
791 | ||
792 | while (*p != NULL) { | |
793 | parent = *p; | |
794 | i = rb_entry(parent, struct srcline_node, rb_node); | |
795 | if (addr < i->addr) | |
796 | p = &(*p)->rb_left; | |
55ecd631 | 797 | else { |
21ac9d54 | 798 | p = &(*p)->rb_right; |
55ecd631 DB |
799 | leftmost = false; |
800 | } | |
21ac9d54 MW |
801 | } |
802 | rb_link_node(&node->rb_node, parent, p); | |
55ecd631 | 803 | rb_insert_color_cached(&node->rb_node, tree, leftmost); |
21ac9d54 MW |
804 | } |
805 | ||
55ecd631 | 806 | char *srcline__tree_find(struct rb_root_cached *tree, u64 addr) |
21ac9d54 | 807 | { |
55ecd631 | 808 | struct rb_node *n = tree->rb_root.rb_node; |
21ac9d54 MW |
809 | |
810 | while (n) { | |
811 | struct srcline_node *i = rb_entry(n, struct srcline_node, | |
812 | rb_node); | |
813 | ||
814 | if (addr < i->addr) | |
815 | n = n->rb_left; | |
816 | else if (addr > i->addr) | |
817 | n = n->rb_right; | |
818 | else | |
819 | return i->srcline; | |
820 | } | |
821 | ||
822 | return NULL; | |
823 | } | |
824 | ||
55ecd631 | 825 | void srcline__tree_delete(struct rb_root_cached *tree) |
21ac9d54 MW |
826 | { |
827 | struct srcline_node *pos; | |
55ecd631 | 828 | struct rb_node *next = rb_first_cached(tree); |
21ac9d54 MW |
829 | |
830 | while (next) { | |
831 | pos = rb_entry(next, struct srcline_node, rb_node); | |
832 | next = rb_next(&pos->rb_node); | |
55ecd631 | 833 | rb_erase_cached(&pos->rb_node, tree); |
21ac9d54 MW |
834 | free_srcline(pos->srcline); |
835 | zfree(&pos); | |
836 | } | |
837 | } | |
838 | ||
fea0cf84 MW |
839 | struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr, |
840 | struct symbol *sym) | |
a64489c5 JY |
841 | { |
842 | const char *dso_name; | |
843 | ||
844 | dso_name = dso__name(dso); | |
845 | if (dso_name == NULL) | |
846 | return NULL; | |
847 | ||
fea0cf84 | 848 | return addr2inlines(dso_name, addr, dso, sym); |
a64489c5 JY |
849 | } |
850 | ||
851 | void inline_node__delete(struct inline_node *node) | |
852 | { | |
853 | struct inline_list *ilist, *tmp; | |
854 | ||
855 | list_for_each_entry_safe(ilist, tmp, &node->val, list) { | |
856 | list_del_init(&ilist->list); | |
2be8832f | 857 | free_srcline(ilist->srcline); |
fea0cf84 MW |
858 | /* only the inlined symbols are owned by the list */ |
859 | if (ilist->symbol && ilist->symbol->inlined) | |
860 | symbol__delete(ilist->symbol); | |
a64489c5 JY |
861 | free(ilist); |
862 | } | |
863 | ||
864 | free(node); | |
865 | } | |
11ea2515 | 866 | |
55ecd631 DB |
867 | void inlines__tree_insert(struct rb_root_cached *tree, |
868 | struct inline_node *inlines) | |
11ea2515 | 869 | { |
55ecd631 | 870 | struct rb_node **p = &tree->rb_root.rb_node; |
11ea2515 MW |
871 | struct rb_node *parent = NULL; |
872 | const u64 addr = inlines->addr; | |
873 | struct inline_node *i; | |
55ecd631 | 874 | bool leftmost = true; |
11ea2515 MW |
875 | |
876 | while (*p != NULL) { | |
877 | parent = *p; | |
878 | i = rb_entry(parent, struct inline_node, rb_node); | |
879 | if (addr < i->addr) | |
880 | p = &(*p)->rb_left; | |
55ecd631 | 881 | else { |
11ea2515 | 882 | p = &(*p)->rb_right; |
55ecd631 DB |
883 | leftmost = false; |
884 | } | |
11ea2515 MW |
885 | } |
886 | rb_link_node(&inlines->rb_node, parent, p); | |
55ecd631 | 887 | rb_insert_color_cached(&inlines->rb_node, tree, leftmost); |
11ea2515 MW |
888 | } |
889 | ||
55ecd631 | 890 | struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr) |
11ea2515 | 891 | { |
55ecd631 | 892 | struct rb_node *n = tree->rb_root.rb_node; |
11ea2515 MW |
893 | |
894 | while (n) { | |
895 | struct inline_node *i = rb_entry(n, struct inline_node, | |
896 | rb_node); | |
897 | ||
898 | if (addr < i->addr) | |
899 | n = n->rb_left; | |
900 | else if (addr > i->addr) | |
901 | n = n->rb_right; | |
902 | else | |
903 | return i; | |
904 | } | |
905 | ||
906 | return NULL; | |
907 | } | |
908 | ||
55ecd631 | 909 | void inlines__tree_delete(struct rb_root_cached *tree) |
11ea2515 MW |
910 | { |
911 | struct inline_node *pos; | |
55ecd631 | 912 | struct rb_node *next = rb_first_cached(tree); |
11ea2515 MW |
913 | |
914 | while (next) { | |
915 | pos = rb_entry(next, struct inline_node, rb_node); | |
916 | next = rb_next(&pos->rb_node); | |
55ecd631 | 917 | rb_erase_cached(&pos->rb_node, tree); |
11ea2515 MW |
918 | inline_node__delete(pos); |
919 | } | |
920 | } |