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