File Index
Files and directories
Sign in
FILE

srcline.c

File preview with syntax highlighting.

linux-6.19.14/tools/perf/util/srcline.c C
  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
 13bool srcline_full_filename;
 14
 15char *srcline__unknown = (char *)"??:0";
 16
 17static 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
 35int 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 */
 55static const char *gnu_basename(const char *path)
 56{
 57	const char *base = strrchr(path, '/');
 58
 59	return base ? base + 1 : path;
 60}
 61
 62char *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
 78struct 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
117static 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
134static 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
160char *__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
190out_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	}
196out:
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 */
211char *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
230out_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
240void 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
251char *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
257struct srcline_node {
258	u64			addr;
259	char			*srcline;
260	struct rb_node		rb_node;
261};
262
263void 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
293char *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
312void 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
326struct 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
338void 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
354void 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
377struct 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
396void 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}
~/ Read-only file preview.