1 // SPDX-License-Identifier: GPL-2.0
2 #include "srcline.h"
3 #include "addr2line.h"
4 #include "dso.h"
5 #include "callchain.h"
6 #include "libbfd.h"
7 #include "llvm.h"
8 #include "symbol.h"
9 #include "libdw.h"
10 #include "debug.h"
11
12 #include <inttypes.h>
13 #include <string.h>
14 #include <linux/string.h>
15
16 bool srcline_full_filename;
17
18 char *srcline__unknown = (char *)"??:0";
19
srcline_dso_name(struct dso * dso)20 static const char *srcline_dso_name(struct dso *dso)
21 {
22 const char *dso_name;
23
24 if (dso__symsrc_filename(dso))
25 dso_name = dso__symsrc_filename(dso);
26 else
27 dso_name = dso__long_name(dso);
28
29 if (dso_name[0] == '[')
30 return NULL;
31
32 if (is_perf_pid_map_name(dso_name))
33 return NULL;
34
35 return dso_name;
36 }
37
inline_list__append(struct symbol * symbol,char * srcline,struct inline_node * node)38 int inline_list__append(struct symbol *symbol, char *srcline, struct inline_node *node)
39 {
40 struct inline_list *ilist;
41
42 ilist = zalloc(sizeof(*ilist));
43 if (ilist == NULL)
44 return -1;
45
46 ilist->symbol = symbol;
47 ilist->srcline = srcline;
48
49 if (callchain_param.order == ORDER_CALLEE)
50 list_add_tail(&ilist->list, &node->val);
51 else
52 list_add(&ilist->list, &node->val);
53
54 return 0;
55 }
56
inline_list__append_tail(struct symbol * symbol,char * srcline,struct inline_node * node)57 int inline_list__append_tail(struct symbol *symbol, char *srcline, struct inline_node *node)
58 {
59 struct inline_list *ilist;
60
61 ilist = zalloc(sizeof(*ilist));
62 if (ilist == NULL)
63 return -1;
64
65 ilist->symbol = symbol;
66 ilist->srcline = srcline;
67
68 if (callchain_param.order == ORDER_CALLEE)
69 list_add(&ilist->list, &node->val);
70 else
71 list_add_tail(&ilist->list, &node->val);
72
73 return 0;
74 }
75
76 /* basename version that takes a const input string */
gnu_basename(const char * path)77 static const char *gnu_basename(const char *path)
78 {
79 const char *base = strrchr(path, '/');
80
81 return base ? base + 1 : path;
82 }
83
srcline_from_fileline(const char * file,unsigned int line)84 char *srcline_from_fileline(const char *file, unsigned int line)
85 {
86 char *srcline;
87
88 if (!file)
89 return NULL;
90
91 if (!srcline_full_filename)
92 file = gnu_basename(file);
93
94 if (asprintf(&srcline, "%s:%u", file, line) < 0)
95 return NULL;
96
97 return srcline;
98 }
99
new_inline_sym(struct dso * dso,struct symbol * base_sym,const char * funcname)100 struct symbol *new_inline_sym(struct dso *dso,
101 struct symbol *base_sym,
102 const char *funcname)
103 {
104 struct symbol *inline_sym;
105 char *demangled = NULL;
106
107 if (!funcname)
108 funcname = "??";
109
110 if (dso) {
111 demangled = dso__demangle_sym(dso, 0, funcname);
112 if (demangled)
113 funcname = demangled;
114 }
115
116 if (base_sym && strcmp(funcname, base_sym->name) == 0) {
117 /* reuse the real, existing symbol */
118 inline_sym = base_sym;
119 /* ensure that we don't alias an inlined symbol, which could
120 * lead to double frees in inline_node__delete
121 */
122 assert(!base_sym->inlined);
123 } else {
124 /* create a fake symbol for the inline frame */
125 inline_sym = symbol__new(base_sym ? base_sym->start : 0,
126 base_sym ? (base_sym->end - base_sym->start) : 0,
127 base_sym ? base_sym->binding : 0,
128 base_sym ? base_sym->type : 0,
129 funcname);
130 if (inline_sym)
131 inline_sym->inlined = 1;
132 }
133
134 free(demangled);
135
136 return inline_sym;
137 }
138
addr2line(const char * dso_name,u64 addr,char ** file,unsigned int * line_nr,struct dso * dso,bool unwind_inlines,struct inline_node * node,struct symbol * sym)139 static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr,
140 struct dso *dso, bool unwind_inlines, struct inline_node *node,
141 struct symbol *sym)
142 {
143 int ret = 0;
144
145 if (symbol_conf.addr2line_style[0] == A2L_STYLE_UNKNOWN) {
146 int i = 0;
147
148 /* Default addr2line fallback order. */
149 #ifdef HAVE_LIBDW_SUPPORT
150 symbol_conf.addr2line_style[i++] = A2L_STYLE_LIBDW;
151 #endif
152 #ifdef HAVE_LIBLLVM_SUPPORT
153 symbol_conf.addr2line_style[i++] = A2L_STYLE_LLVM;
154 #endif
155 #ifdef HAVE_LIBBFD_SUPPORT
156 symbol_conf.addr2line_style[i++] = A2L_STYLE_LIBBFD;
157 #endif
158 symbol_conf.addr2line_style[i++] = A2L_STYLE_CMD;
159 }
160
161 for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.addr2line_style); i++) {
162 switch (symbol_conf.addr2line_style[i]) {
163 case A2L_STYLE_LIBDW:
164 ret = libdw__addr2line(addr, file, line_nr, dso, unwind_inlines,
165 node, sym);
166 break;
167 case A2L_STYLE_LLVM:
168 ret = llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines,
169 node, sym);
170 break;
171 case A2L_STYLE_LIBBFD:
172 ret = libbfd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines,
173 node, sym);
174 break;
175 case A2L_STYLE_CMD:
176 ret = cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines,
177 node, sym);
178 break;
179 case A2L_STYLE_UNKNOWN:
180 default:
181 break;
182 }
183 if (ret > 0)
184 return ret;
185 }
186
187 return 0;
188 }
189
addr2line_configure(const char * var,const char * value,void * cb __maybe_unused)190 int addr2line_configure(const char *var, const char *value, void *cb __maybe_unused)
191 {
192 static const char * const a2l_style_names[] = {
193 [A2L_STYLE_LIBDW] = "libdw",
194 [A2L_STYLE_LLVM] = "llvm",
195 [A2L_STYLE_LIBBFD] = "libbfd",
196 [A2L_STYLE_CMD] = "addr2line",
197 NULL
198 };
199
200 char *s, *p, *saveptr;
201 size_t i = 0;
202
203 if (strcmp(var, "addr2line.style"))
204 return 0;
205
206 if (!value)
207 return -1;
208
209 s = strdup(value);
210 if (!s)
211 return -1;
212
213 p = strtok_r(s, ",", &saveptr);
214 while (p && i < ARRAY_SIZE(symbol_conf.addr2line_style)) {
215 bool found = false;
216 char *q = strim(p);
217
218 for (size_t j = A2L_STYLE_LIBDW; j < MAX_A2L_STYLE; j++) {
219 if (!strcasecmp(q, a2l_style_names[j])) {
220 symbol_conf.addr2line_style[i++] = j;
221 found = true;
222 break;
223 }
224 }
225 if (!found)
226 pr_warning("Unknown addr2line style: %s\n", q);
227 p = strtok_r(NULL, ",", &saveptr);
228 }
229
230 free(s);
231 return 0;
232 }
233
addr2inlines(const char * dso_name,u64 addr,struct dso * dso,struct symbol * sym)234 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
235 struct dso *dso, struct symbol *sym)
236 {
237 struct inline_node *node;
238
239 node = zalloc(sizeof(*node));
240 if (node == NULL) {
241 perror("not enough memory for the inline node");
242 return NULL;
243 }
244
245 INIT_LIST_HEAD(&node->val);
246 node->addr = addr;
247
248 addr2line(dso_name, addr, /*file=*/NULL, /*line_nr=*/NULL, dso,
249 /*unwind_inlines=*/true, node, sym);
250
251 return node;
252 }
253
254 /*
255 * Number of addr2line failures (without success) before disabling it for that
256 * dso.
257 */
258 #define A2L_FAIL_LIMIT 123
259
__get_srcline(struct dso * dso,u64 addr,struct symbol * sym,bool show_sym,bool show_addr,bool unwind_inlines,u64 ip)260 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
261 bool show_sym, bool show_addr, bool unwind_inlines,
262 u64 ip)
263 {
264 char *file = NULL;
265 unsigned line = 0;
266 char *srcline;
267 const char *dso_name;
268
269 if (!dso__has_srcline(dso))
270 goto out;
271
272 dso_name = srcline_dso_name(dso);
273 if (dso_name == NULL)
274 goto out_err;
275
276 if (!addr2line(dso_name, addr, &file, &line, dso,
277 unwind_inlines, /*node=*/NULL, sym))
278 goto out_err;
279
280 srcline = srcline_from_fileline(file, line);
281 free(file);
282
283 if (!srcline)
284 goto out_err;
285
286 dso__set_a2l_fails(dso, 0);
287
288 return srcline;
289
290 out_err:
291 dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1);
292 if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) {
293 dso__set_has_srcline(dso, false);
294 dso__free_a2l(dso);
295 }
296 out:
297 if (!show_addr)
298 return (show_sym && sym) ?
299 strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN;
300
301 if (sym) {
302 if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
303 ip - sym->start) < 0)
304 return SRCLINE_UNKNOWN;
305 } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso__short_name(dso), addr) < 0)
306 return SRCLINE_UNKNOWN;
307 return srcline;
308 }
309
310 /* Returns filename and fills in line number in line */
get_srcline_split(struct dso * dso,u64 addr,unsigned * line)311 char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
312 {
313 char *file = NULL;
314 const char *dso_name;
315
316 if (!dso__has_srcline(dso))
317 return NULL;
318
319 dso_name = srcline_dso_name(dso);
320 if (dso_name == NULL)
321 goto out_err;
322
323 if (!addr2line(dso_name, addr, &file, line, dso, /*unwind_inlines=*/true,
324 /*node=*/NULL, /*sym=*/NULL))
325 goto out_err;
326
327 dso__set_a2l_fails(dso, 0);
328 return file;
329
330 out_err:
331 dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1);
332 if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) {
333 dso__set_has_srcline(dso, false);
334 dso__free_a2l(dso);
335 }
336
337 return NULL;
338 }
339
zfree_srcline(char ** srcline)340 void zfree_srcline(char **srcline)
341 {
342 if (*srcline == NULL)
343 return;
344
345 if (*srcline != SRCLINE_UNKNOWN)
346 free(*srcline);
347
348 *srcline = NULL;
349 }
350
get_srcline(struct dso * dso,u64 addr,struct symbol * sym,bool show_sym,bool show_addr,u64 ip)351 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
352 bool show_sym, bool show_addr, u64 ip)
353 {
354 return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip);
355 }
356
357 struct srcline_node {
358 u64 addr;
359 char *srcline;
360 struct rb_node rb_node;
361 };
362
srcline__tree_insert(struct rb_root_cached * tree,u64 addr,char * srcline)363 void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline)
364 {
365 struct rb_node **p = &tree->rb_root.rb_node;
366 struct rb_node *parent = NULL;
367 struct srcline_node *i, *node;
368 bool leftmost = true;
369
370 node = zalloc(sizeof(struct srcline_node));
371 if (!node) {
372 perror("not enough memory for the srcline node");
373 return;
374 }
375
376 node->addr = addr;
377 node->srcline = srcline;
378
379 while (*p != NULL) {
380 parent = *p;
381 i = rb_entry(parent, struct srcline_node, rb_node);
382 if (addr < i->addr)
383 p = &(*p)->rb_left;
384 else {
385 p = &(*p)->rb_right;
386 leftmost = false;
387 }
388 }
389 rb_link_node(&node->rb_node, parent, p);
390 rb_insert_color_cached(&node->rb_node, tree, leftmost);
391 }
392
srcline__tree_find(struct rb_root_cached * tree,u64 addr)393 char *srcline__tree_find(struct rb_root_cached *tree, u64 addr)
394 {
395 struct rb_node *n = tree->rb_root.rb_node;
396
397 while (n) {
398 struct srcline_node *i = rb_entry(n, struct srcline_node,
399 rb_node);
400
401 if (addr < i->addr)
402 n = n->rb_left;
403 else if (addr > i->addr)
404 n = n->rb_right;
405 else
406 return i->srcline;
407 }
408
409 return NULL;
410 }
411
srcline__tree_delete(struct rb_root_cached * tree)412 void srcline__tree_delete(struct rb_root_cached *tree)
413 {
414 struct srcline_node *pos;
415 struct rb_node *next = rb_first_cached(tree);
416
417 while (next) {
418 pos = rb_entry(next, struct srcline_node, rb_node);
419 next = rb_next(&pos->rb_node);
420 rb_erase_cached(&pos->rb_node, tree);
421 zfree_srcline(&pos->srcline);
422 zfree(&pos);
423 }
424 }
425
dso__parse_addr_inlines(struct dso * dso,u64 addr,struct symbol * sym)426 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
427 struct symbol *sym)
428 {
429 const char *dso_name;
430
431 dso_name = srcline_dso_name(dso);
432 if (dso_name == NULL)
433 return NULL;
434
435 return addr2inlines(dso_name, addr, dso, sym);
436 }
437
inline_node__delete(struct inline_node * node)438 void inline_node__delete(struct inline_node *node)
439 {
440 struct inline_list *ilist, *tmp;
441
442 list_for_each_entry_safe(ilist, tmp, &node->val, list) {
443 list_del_init(&ilist->list);
444 zfree_srcline(&ilist->srcline);
445 /* only the inlined symbols are owned by the list */
446 if (ilist->symbol && ilist->symbol->inlined)
447 symbol__delete(ilist->symbol);
448 free(ilist);
449 }
450
451 free(node);
452 }
453
inlines__tree_insert(struct rb_root_cached * tree,struct inline_node * inlines)454 void inlines__tree_insert(struct rb_root_cached *tree,
455 struct inline_node *inlines)
456 {
457 struct rb_node **p = &tree->rb_root.rb_node;
458 struct rb_node *parent = NULL;
459 const u64 addr = inlines->addr;
460 struct inline_node *i;
461 bool leftmost = true;
462
463 while (*p != NULL) {
464 parent = *p;
465 i = rb_entry(parent, struct inline_node, rb_node);
466 if (addr < i->addr)
467 p = &(*p)->rb_left;
468 else {
469 p = &(*p)->rb_right;
470 leftmost = false;
471 }
472 }
473 rb_link_node(&inlines->rb_node, parent, p);
474 rb_insert_color_cached(&inlines->rb_node, tree, leftmost);
475 }
476
inlines__tree_find(struct rb_root_cached * tree,u64 addr)477 struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr)
478 {
479 struct rb_node *n = tree->rb_root.rb_node;
480
481 while (n) {
482 struct inline_node *i = rb_entry(n, struct inline_node,
483 rb_node);
484
485 if (addr < i->addr)
486 n = n->rb_left;
487 else if (addr > i->addr)
488 n = n->rb_right;
489 else
490 return i;
491 }
492
493 return NULL;
494 }
495
inlines__tree_delete(struct rb_root_cached * tree)496 void inlines__tree_delete(struct rb_root_cached *tree)
497 {
498 struct inline_node *pos;
499 struct rb_node *next = rb_first_cached(tree);
500
501 while (next) {
502 pos = rb_entry(next, struct inline_node, rb_node);
503 next = rb_next(&pos->rb_node);
504 rb_erase_cached(&pos->rb_node, tree);
505 inline_node__delete(pos);
506 }
507 }
508