aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJin Yao <yao.jin@linux.intel.com>2017-03-25 16:34:26 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2017-03-27 11:00:38 -0400
commita64489c56c307bf0955f0489158c5ecf6aa10fe2 (patch)
treec509e096dd947ec390f3ec30d82f925e2e04763c
parent5580338d0f207921bc1fef5b668cd564adcc3419 (diff)
perf report: Find the inline stack for a given address
It would be useful for perf to support a mode to query the inline stack for a given callgraph address. This would simplify finding the right code in code that does a lot of inlining. The srcline.c has contained the code which supports to translate the address to filename:line_nr. This patch just extends the function to let it support getting the inline stacks. It introduces the inline_list which will store the inline function result (filename:line_nr and funcname). If BFD lib is not supported, the result is only filename:line_nr. Signed-off-by: Yao Jin <yao.jin@linux.intel.com> Tested-by: Milian Wolff <milian.wolff@kdab.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@intel.com> Link: http://lkml.kernel.org/r/1490474069-15823-3-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/srcline.c167
-rw-r--r--tools/perf/util/symbol-elf.c5
-rw-r--r--tools/perf/util/symbol-minimal.c7
-rw-r--r--tools/perf/util/symbol.h2
-rw-r--r--tools/perf/util/util.h16
5 files changed, 192 insertions, 5 deletions
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 2953c9fecb30..3ce28f702b36 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -7,6 +7,7 @@
7#include "util/dso.h" 7#include "util/dso.h"
8#include "util/util.h" 8#include "util/util.h"
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/callchain.h"
10 11
11#include "symbol.h" 12#include "symbol.h"
12 13
@@ -30,6 +31,34 @@ static const char *dso__name(struct dso *dso)
30 return dso_name; 31 return dso_name;
31} 32}
32 33
34static int inline_list__append(char *filename, char *funcname, int line_nr,
35 struct inline_node *node, struct dso *dso)
36{
37 struct inline_list *ilist;
38 char *demangled;
39
40 ilist = zalloc(sizeof(*ilist));
41 if (ilist == NULL)
42 return -1;
43
44 ilist->filename = filename;
45 ilist->line_nr = line_nr;
46
47 if (dso != NULL) {
48 demangled = dso__demangle_sym(dso, 0, funcname);
49 if (demangled == NULL) {
50 ilist->funcname = funcname;
51 } else {
52 ilist->funcname = demangled;
53 free(funcname);
54 }
55 }
56
57 list_add_tail(&ilist->list, &node->val);
58
59 return 0;
60}
61
33#ifdef HAVE_LIBBFD_SUPPORT 62#ifdef HAVE_LIBBFD_SUPPORT
34 63
35/* 64/*
@@ -169,9 +198,17 @@ static void addr2line_cleanup(struct a2l_data *a2l)
169 198
170#define MAX_INLINE_NEST 1024 199#define MAX_INLINE_NEST 1024
171 200
201static void inline_list__reverse(struct inline_node *node)
202{
203 struct inline_list *ilist, *n;
204
205 list_for_each_entry_safe_reverse(ilist, n, &node->val, list)
206 list_move_tail(&ilist->list, &node->val);
207}
208
172static int addr2line(const char *dso_name, u64 addr, 209static int addr2line(const char *dso_name, u64 addr,
173 char **file, unsigned int *line, struct dso *dso, 210 char **file, unsigned int *line, struct dso *dso,
174 bool unwind_inlines) 211 bool unwind_inlines, struct inline_node *node)
175{ 212{
176 int ret = 0; 213 int ret = 0;
177 struct a2l_data *a2l = dso->a2l; 214 struct a2l_data *a2l = dso->a2l;
@@ -196,8 +233,21 @@ static int addr2line(const char *dso_name, u64 addr,
196 233
197 while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, 234 while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
198 &a2l->funcname, &a2l->line) && 235 &a2l->funcname, &a2l->line) &&
199 cnt++ < MAX_INLINE_NEST) 236 cnt++ < MAX_INLINE_NEST) {
200 ; 237
238 if (node != NULL) {
239 if (inline_list__append(strdup(a2l->filename),
240 strdup(a2l->funcname),
241 a2l->line, node,
242 dso) != 0)
243 return 0;
244 }
245 }
246
247 if ((node != NULL) &&
248 (callchain_param.order != ORDER_CALLEE)) {
249 inline_list__reverse(node);
250 }
201 } 251 }
202 252
203 if (a2l->found && a2l->filename) { 253 if (a2l->found && a2l->filename) {
@@ -223,6 +273,35 @@ void dso__free_a2l(struct dso *dso)
223 dso->a2l = NULL; 273 dso->a2l = NULL;
224} 274}
225 275
276static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
277 struct dso *dso)
278{
279 char *file = NULL;
280 unsigned int line = 0;
281 struct inline_node *node;
282
283 node = zalloc(sizeof(*node));
284 if (node == NULL) {
285 perror("not enough memory for the inline node");
286 return NULL;
287 }
288
289 INIT_LIST_HEAD(&node->val);
290 node->addr = addr;
291
292 if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node))
293 goto out_free_inline_node;
294
295 if (list_empty(&node->val))
296 goto out_free_inline_node;
297
298 return node;
299
300out_free_inline_node:
301 inline_node__delete(node);
302 return NULL;
303}
304
226#else /* HAVE_LIBBFD_SUPPORT */ 305#else /* HAVE_LIBBFD_SUPPORT */
227 306
228static int filename_split(char *filename, unsigned int *line_nr) 307static int filename_split(char *filename, unsigned int *line_nr)
@@ -249,7 +328,8 @@ static int filename_split(char *filename, unsigned int *line_nr)
249static int addr2line(const char *dso_name, u64 addr, 328static int addr2line(const char *dso_name, u64 addr,
250 char **file, unsigned int *line_nr, 329 char **file, unsigned int *line_nr,
251 struct dso *dso __maybe_unused, 330 struct dso *dso __maybe_unused,
252 bool unwind_inlines __maybe_unused) 331 bool unwind_inlines __maybe_unused,
332 struct inline_node *node __maybe_unused)
253{ 333{
254 FILE *fp; 334 FILE *fp;
255 char cmd[PATH_MAX]; 335 char cmd[PATH_MAX];
@@ -288,6 +368,58 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
288{ 368{
289} 369}
290 370
371static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
372 struct dso *dso __maybe_unused)
373{
374 FILE *fp;
375 char cmd[PATH_MAX];
376 struct inline_node *node;
377 char *filename = NULL;
378 size_t len;
379 unsigned int line_nr = 0;
380
381 scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
382 dso_name, addr);
383
384 fp = popen(cmd, "r");
385 if (fp == NULL) {
386 pr_err("popen failed for %s\n", dso_name);
387 return NULL;
388 }
389
390 node = zalloc(sizeof(*node));
391 if (node == NULL) {
392 perror("not enough memory for the inline node");
393 goto out;
394 }
395
396 INIT_LIST_HEAD(&node->val);
397 node->addr = addr;
398
399 while (getline(&filename, &len, fp) != -1) {
400 if (filename_split(filename, &line_nr) != 1) {
401 free(filename);
402 goto out;
403 }
404
405 if (inline_list__append(filename, NULL, line_nr, node,
406 NULL) != 0)
407 goto out;
408
409 filename = NULL;
410 }
411
412out:
413 pclose(fp);
414
415 if (list_empty(&node->val)) {
416 inline_node__delete(node);
417 return NULL;
418 }
419
420 return node;
421}
422
291#endif /* HAVE_LIBBFD_SUPPORT */ 423#endif /* HAVE_LIBBFD_SUPPORT */
292 424
293/* 425/*
@@ -311,7 +443,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
311 if (dso_name == NULL) 443 if (dso_name == NULL)
312 goto out; 444 goto out;
313 445
314 if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines)) 446 if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
315 goto out; 447 goto out;
316 448
317 if (asprintf(&srcline, "%s:%u", 449 if (asprintf(&srcline, "%s:%u",
@@ -351,3 +483,28 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
351{ 483{
352 return __get_srcline(dso, addr, sym, show_sym, false); 484 return __get_srcline(dso, addr, sym, show_sym, false);
353} 485}
486
487struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
488{
489 const char *dso_name;
490
491 dso_name = dso__name(dso);
492 if (dso_name == NULL)
493 return NULL;
494
495 return addr2inlines(dso_name, addr, dso);
496}
497
498void inline_node__delete(struct inline_node *node)
499{
500 struct inline_list *ilist, *tmp;
501
502 list_for_each_entry_safe(ilist, tmp, &node->val, list) {
503 list_del_init(&ilist->list);
504 zfree(&ilist->filename);
505 zfree(&ilist->funcname);
506 free(ilist);
507 }
508
509 free(node);
510}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 0e660dba58ad..d1a40bb642ff 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -390,6 +390,11 @@ out_elf_end:
390 return 0; 390 return 0;
391} 391}
392 392
393char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name)
394{
395 return demangle_sym(dso, kmodule, elf_name);
396}
397
393/* 398/*
394 * Align offset to 4 bytes as needed for note name and descriptor data. 399 * Align offset to 4 bytes as needed for note name and descriptor data.
395 */ 400 */
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 11cdde980545..870ef0f0659c 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -373,3 +373,10 @@ int kcore_copy(const char *from_dir __maybe_unused,
373void symbol__elf_init(void) 373void symbol__elf_init(void)
374{ 374{
375} 375}
376
377char *dso__demangle_sym(struct dso *dso __maybe_unused,
378 int kmodule __maybe_unused,
379 char *elf_name __maybe_unused)
380{
381 return NULL;
382}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 9222c7e702f3..e36213ccfcf7 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -305,6 +305,8 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
305int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, 305int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
306 struct map *map); 306 struct map *map);
307 307
308char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name);
309
308void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel); 310void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel);
309void symbols__insert(struct rb_root *symbols, struct symbol *sym); 311void symbols__insert(struct rb_root *symbols, struct symbol *sym);
310void symbols__fixup_duplicate(struct rb_root *symbols); 312void symbols__fixup_duplicate(struct rb_root *symbols);
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b2cfa47990dc..cc0700d6fef0 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -364,4 +364,20 @@ int is_printable_array(char *p, unsigned int len);
364int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); 364int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
365 365
366int unit_number__scnprintf(char *buf, size_t size, u64 n); 366int unit_number__scnprintf(char *buf, size_t size, u64 n);
367
368struct inline_list {
369 char *filename;
370 char *funcname;
371 unsigned int line_nr;
372 struct list_head list;
373};
374
375struct inline_node {
376 u64 addr;
377 struct list_head val;
378};
379
380struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr);
381void inline_node__delete(struct inline_node *node);
382
367#endif /* GIT_COMPAT_UTIL_H */ 383#endif /* GIT_COMPAT_UTIL_H */