xref: /linux/tools/perf/util/srcline.c (revision ec714e371f22f716a04e6ecb2a24988c92b26911)
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