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
10 #include <inttypes.h>
11 #include <string.h>
12
13 bool srcline_full_filename;
14
15 char *srcline__unknown = (char *)"??:0";
16
srcline_dso_name(struct dso * dso)17 static const char *srcline_dso_name(struct dso *dso)
18 {
19 const char *dso_name;
20
21 if (dso__symsrc_filename(dso))
22 dso_name = dso__symsrc_filename(dso);
23 else
24 dso_name = dso__long_name(dso);
25
26 if (dso_name[0] == '[')
27 return NULL;
28
29 if (is_perf_pid_map_name(dso_name))
30 return NULL;
31
32 return dso_name;
33 }
34
inline_list__append(struct symbol * symbol,char * srcline,struct inline_node * node)35 int inline_list__append(struct symbol *symbol, char *srcline, struct inline_node *node)
36 {
37 struct inline_list *ilist;
38
39 ilist = zalloc(sizeof(*ilist));
40 if (ilist == NULL)
41 return -1;
42
43 ilist->symbol = symbol;
44 ilist->srcline = srcline;
45
46 if (callchain_param.order == ORDER_CALLEE)
47 list_add_tail(&ilist->list, &node->val);
48 else
49 list_add(&ilist->list, &node->val);
50
51 return 0;
52 }
53
54 /* basename version that takes a const input string */
gnu_basename(const char * path)55 static const char *gnu_basename(const char *path)
56 {
57 const char *base = strrchr(path, '/');
58
59 return base ? base + 1 : path;
60 }
61
srcline_from_fileline(const char * file,unsigned int line)62 char *srcline_from_fileline(const char *file, unsigned int line)
63 {
64 char *srcline;
65
66 if (!file)
67 return NULL;
68
69 if (!srcline_full_filename)
70 file = gnu_basename(file);
71
72 if (asprintf(&srcline, "%s:%u", file, line) < 0)
73 return NULL;
74
75 return srcline;
76 }
77
new_inline_sym(struct dso * dso,struct symbol * base_sym,const char * funcname)78 struct symbol *new_inline_sym(struct dso *dso,
79 struct symbol *base_sym,
80 const char *funcname)
81 {
82 struct symbol *inline_sym;
83 char *demangled = NULL;
84
85 if (!funcname)
86 funcname = "??";
87
88 if (dso) {
89 demangled = dso__demangle_sym(dso, 0, funcname);
90 if (demangled)
91 funcname = demangled;
92 }
93
94 if (base_sym && strcmp(funcname, base_sym->name) == 0) {
95 /* reuse the real, existing symbol */
96 inline_sym = base_sym;
97 /* ensure that we don't alias an inlined symbol, which could
98 * lead to double frees in inline_node__delete
99 */
100 assert(!base_sym->inlined);
101 } else {
102 /* create a fake symbol for the inline frame */
103 inline_sym = symbol__new(base_sym ? base_sym->start : 0,
104 base_sym ? (base_sym->end - base_sym->start) : 0,
105 base_sym ? base_sym->binding : 0,
106 base_sym ? base_sym->type : 0,
107 funcname);
108 if (inline_sym)
109 inline_sym->inlined = 1;
110 }
111
112 free(demangled);
113
114 return inline_sym;
115 }
116
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)117 static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr,
118 struct dso *dso, bool unwind_inlines, struct inline_node *node,
119 struct symbol *sym)
120 {
121 int ret;
122
123 ret = llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym);
124 if (ret > 0)
125 return ret;
126
127 ret = libbfd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym);
128 if (ret > 0)
129 return ret;
130
131 return cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym);
132 }
133
addr2inlines(const char * dso_name,u64 addr,struct dso * dso,struct symbol * sym)134 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
135 struct dso *dso, struct symbol *sym)
136 {
137 struct inline_node *node;
138
139 node = zalloc(sizeof(*node));
140 if (node == NULL) {
141 perror("not enough memory for the inline node");
142 return NULL;
143 }
144
145 INIT_LIST_HEAD(&node->val);
146 node->addr = addr;
147
148 addr2line(dso_name, addr, /*file=*/NULL, /*line_nr=*/NULL, dso,
149 /*unwind_inlines=*/true, node, sym);
150
151 return node;
152 }
153
154 /*
155 * Number of addr2line failures (without success) before disabling it for that
156 * dso.
157 */
158 #define A2L_FAIL_LIMIT 123
159
__get_srcline(struct dso * dso,u64 addr,struct symbol * sym,bool show_sym,bool show_addr,bool unwind_inlines,u64 ip)160 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
161 bool show_sym, bool show_addr, bool unwind_inlines,
162 u64 ip)
163 {
164 char *file = NULL;
165 unsigned line = 0;
166 char *srcline;
167 const char *dso_name;
168
169 if (!dso__has_srcline(dso))
170 goto out;
171
172 dso_name = srcline_dso_name(dso);
173 if (dso_name == NULL)
174 goto out_err;
175
176 if (!addr2line(dso_name, addr, &file, &line, dso,
177 unwind_inlines, /*node=*/NULL, sym))
178 goto out_err;
179
180 srcline = srcline_from_fileline(file, line);
181 free(file);
182
183 if (!srcline)
184 goto out_err;
185
186 dso__set_a2l_fails(dso, 0);
187
188 return srcline;
189
190 out_err:
191 dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1);
192 if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) {
193 dso__set_has_srcline(dso, false);
194 dso__free_a2l(dso);
195 }
196 out:
197 if (!show_addr)
198 return (show_sym && sym) ?
199 strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN;
200
201 if (sym) {
202 if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
203 ip - sym->start) < 0)
204 return SRCLINE_UNKNOWN;
205 } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso__short_name(dso), addr) < 0)
206 return SRCLINE_UNKNOWN;
207 return srcline;
208 }
209
210 /* Returns filename and fills in line number in line */
get_srcline_split(struct dso * dso,u64 addr,unsigned * line)211 char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
212 {
213 char *file = NULL;
214 const char *dso_name;
215
216 if (!dso__has_srcline(dso))
217 return NULL;
218
219 dso_name = srcline_dso_name(dso);
220 if (dso_name == NULL)
221 goto out_err;
222
223 if (!addr2line(dso_name, addr, &file, line, dso, /*unwind_inlines=*/true,
224 /*node=*/NULL, /*sym=*/NULL))
225 goto out_err;
226
227 dso__set_a2l_fails(dso, 0);
228 return file;
229
230 out_err:
231 dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1);
232 if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) {
233 dso__set_has_srcline(dso, false);
234 dso__free_a2l(dso);
235 }
236
237 return NULL;
238 }
239
zfree_srcline(char ** srcline)240 void zfree_srcline(char **srcline)
241 {
242 if (*srcline == NULL)
243 return;
244
245 if (*srcline != SRCLINE_UNKNOWN)
246 free(*srcline);
247
248 *srcline = NULL;
249 }
250
get_srcline(struct dso * dso,u64 addr,struct symbol * sym,bool show_sym,bool show_addr,u64 ip)251 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
252 bool show_sym, bool show_addr, u64 ip)
253 {
254 return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip);
255 }
256
257 struct srcline_node {
258 u64 addr;
259 char *srcline;
260 struct rb_node rb_node;
261 };
262
srcline__tree_insert(struct rb_root_cached * tree,u64 addr,char * srcline)263 void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline)
264 {
265 struct rb_node **p = &tree->rb_root.rb_node;
266 struct rb_node *parent = NULL;
267 struct srcline_node *i, *node;
268 bool leftmost = true;
269
270 node = zalloc(sizeof(struct srcline_node));
271 if (!node) {
272 perror("not enough memory for the srcline node");
273 return;
274 }
275
276 node->addr = addr;
277 node->srcline = srcline;
278
279 while (*p != NULL) {
280 parent = *p;
281 i = rb_entry(parent, struct srcline_node, rb_node);
282 if (addr < i->addr)
283 p = &(*p)->rb_left;
284 else {
285 p = &(*p)->rb_right;
286 leftmost = false;
287 }
288 }
289 rb_link_node(&node->rb_node, parent, p);
290 rb_insert_color_cached(&node->rb_node, tree, leftmost);
291 }
292
srcline__tree_find(struct rb_root_cached * tree,u64 addr)293 char *srcline__tree_find(struct rb_root_cached *tree, u64 addr)
294 {
295 struct rb_node *n = tree->rb_root.rb_node;
296
297 while (n) {
298 struct srcline_node *i = rb_entry(n, struct srcline_node,
299 rb_node);
300
301 if (addr < i->addr)
302 n = n->rb_left;
303 else if (addr > i->addr)
304 n = n->rb_right;
305 else
306 return i->srcline;
307 }
308
309 return NULL;
310 }
311
srcline__tree_delete(struct rb_root_cached * tree)312 void srcline__tree_delete(struct rb_root_cached *tree)
313 {
314 struct srcline_node *pos;
315 struct rb_node *next = rb_first_cached(tree);
316
317 while (next) {
318 pos = rb_entry(next, struct srcline_node, rb_node);
319 next = rb_next(&pos->rb_node);
320 rb_erase_cached(&pos->rb_node, tree);
321 zfree_srcline(&pos->srcline);
322 zfree(&pos);
323 }
324 }
325
dso__parse_addr_inlines(struct dso * dso,u64 addr,struct symbol * sym)326 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
327 struct symbol *sym)
328 {
329 const char *dso_name;
330
331 dso_name = srcline_dso_name(dso);
332 if (dso_name == NULL)
333 return NULL;
334
335 return addr2inlines(dso_name, addr, dso, sym);
336 }
337
inline_node__delete(struct inline_node * node)338 void inline_node__delete(struct inline_node *node)
339 {
340 struct inline_list *ilist, *tmp;
341
342 list_for_each_entry_safe(ilist, tmp, &node->val, list) {
343 list_del_init(&ilist->list);
344 zfree_srcline(&ilist->srcline);
345 /* only the inlined symbols are owned by the list */
346 if (ilist->symbol && ilist->symbol->inlined)
347 symbol__delete(ilist->symbol);
348 free(ilist);
349 }
350
351 free(node);
352 }
353
inlines__tree_insert(struct rb_root_cached * tree,struct inline_node * inlines)354 void inlines__tree_insert(struct rb_root_cached *tree,
355 struct inline_node *inlines)
356 {
357 struct rb_node **p = &tree->rb_root.rb_node;
358 struct rb_node *parent = NULL;
359 const u64 addr = inlines->addr;
360 struct inline_node *i;
361 bool leftmost = true;
362
363 while (*p != NULL) {
364 parent = *p;
365 i = rb_entry(parent, struct inline_node, rb_node);
366 if (addr < i->addr)
367 p = &(*p)->rb_left;
368 else {
369 p = &(*p)->rb_right;
370 leftmost = false;
371 }
372 }
373 rb_link_node(&inlines->rb_node, parent, p);
374 rb_insert_color_cached(&inlines->rb_node, tree, leftmost);
375 }
376
inlines__tree_find(struct rb_root_cached * tree,u64 addr)377 struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr)
378 {
379 struct rb_node *n = tree->rb_root.rb_node;
380
381 while (n) {
382 struct inline_node *i = rb_entry(n, struct inline_node,
383 rb_node);
384
385 if (addr < i->addr)
386 n = n->rb_left;
387 else if (addr > i->addr)
388 n = n->rb_right;
389 else
390 return i;
391 }
392
393 return NULL;
394 }
395
inlines__tree_delete(struct rb_root_cached * tree)396 void inlines__tree_delete(struct rb_root_cached *tree)
397 {
398 struct inline_node *pos;
399 struct rb_node *next = rb_first_cached(tree);
400
401 while (next) {
402 pos = rb_entry(next, struct inline_node, rb_node);
403 next = rb_next(&pos->rb_node);
404 rb_erase_cached(&pos->rb_node, tree);
405 inline_node__delete(pos);
406 }
407 }
408