Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935497AbdCXShy (ORCPT ); Fri, 24 Mar 2017 14:37:54 -0400 Received: from mail.kernel.org ([198.145.29.136]:60906 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751920AbdCXShp (ORCPT ); Fri, 24 Mar 2017 14:37:45 -0400 Date: Fri, 24 Mar 2017 15:37:37 -0300 From: Arnaldo Carvalho de Melo To: Jin Yao Cc: jolsa@kernel.org, Linux-kernel@vger.kernel.org, ak@linux.intel.com, kan.liang@intel.com, milian.wolff@kdab.com, yao.jin@intel.com Subject: Re: [PATCH v5 2/5] perf report: Find the inline stack for a given address Message-ID: <20170324183737.GD5148@kernel.org> References: <1489700547-7260-1-git-send-email-yao.jin@linux.intel.com> <1489700547-7260-3-git-send-email-yao.jin@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1489700547-7260-3-git-send-email-yao.jin@linux.intel.com> X-Url: http://acmel.wordpress.com User-Agent: Mutt/1.8.0 (2017-02-23) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8844 Lines: 313 Em Fri, Mar 17, 2017 at 05:42:24AM +0800, Jin Yao escreveu: > 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). > > Signed-off-by: Jin Yao > Tested-by: Milian Wolff > --- > tools/perf/util/srcline.c | 169 +++++++++++++++++++++++++++++++++++++++++-- > tools/perf/util/symbol-elf.c | 5 ++ > tools/perf/util/symbol.h | 2 + > tools/perf/util/util.h | 16 ++++ > 4 files changed, 187 insertions(+), 5 deletions(-) > > diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c > index 2953c9f..f9d4b47 100644 > --- a/tools/perf/util/srcline.c > +++ b/tools/perf/util/srcline.c > @@ -7,6 +7,7 @@ > #include "util/dso.h" > #include "util/util.h" > #include "util/debug.h" > +#include "util/callchain.h" > > #include "symbol.h" > > @@ -30,6 +31,41 @@ static const char *dso__name(struct dso *dso) > return dso_name; > } > > +static int inline_list__append(char *filename, char *funcname, int line_nr, > + struct inline_node *node, struct dso *dso) > +{ > + struct inline_list *ilist; > + char *demangled; > + > + ilist = zalloc(sizeof(*ilist)); > + if (ilist == NULL) > + return -1; > + > + ilist->filename = filename; > + ilist->line_nr = line_nr; > + > + demangled = dso__demangle_sym(dso, 0, funcname); > + if (demangled == NULL) { > + ilist->funcname = funcname; > + } else { > + ilist->funcname = demangled; > + if (funcname != NULL) > + free(funcname); free() can be fed NULL, I'll simplify this thus > + } > + > + list_add_tail(&ilist->list, &node->val); > + > + return 0; > +} > + > +static void inline_list__reverse(struct inline_node *node) > +{ > + struct inline_list *ilist, *n; > + > + list_for_each_entry_safe_reverse(ilist, n, &node->val, list) > + list_move_tail(&ilist->list, &node->val); > +} > + > #ifdef HAVE_LIBBFD_SUPPORT > > /* > @@ -171,7 +207,7 @@ static void addr2line_cleanup(struct a2l_data *a2l) > > static int addr2line(const char *dso_name, u64 addr, > char **file, unsigned int *line, struct dso *dso, > - bool unwind_inlines) > + bool unwind_inlines, struct inline_node *node) > { > int ret = 0; > struct a2l_data *a2l = dso->a2l; > @@ -196,8 +232,21 @@ static int addr2line(const char *dso_name, u64 addr, > > while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, > &a2l->funcname, &a2l->line) && > - cnt++ < MAX_INLINE_NEST) > - ; > + cnt++ < MAX_INLINE_NEST) { > + > + if (node != NULL) { > + if (inline_list__append(strdup(a2l->filename), > + strdup(a2l->funcname), > + a2l->line, node, > + dso) != 0) > + return 0; > + } > + } > + > + if ((node != NULL) && > + (callchain_param.order != ORDER_CALLEE)) { > + inline_list__reverse(node); > + } > } > > if (a2l->found && a2l->filename) { > @@ -223,6 +272,35 @@ void dso__free_a2l(struct dso *dso) > dso->a2l = NULL; > } > > +static struct inline_node *addr2inlines(const char *dso_name, u64 addr, > + struct dso *dso) > +{ > + char *file = NULL; > + unsigned int line = 0; > + struct inline_node *node; > + > + node = zalloc(sizeof(*node)); > + if (node == NULL) { > + perror("not enough memory for the inline node"); > + return NULL; > + } > + > + INIT_LIST_HEAD(&node->val); > + node->addr = addr; > + > + if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node)) > + goto out_free_inline_node; > + > + if (list_empty(&node->val)) > + goto out_free_inline_node; > + > + return node; > + > +out_free_inline_node: > + inline_node__delete(node); > + return NULL; > +} > + > #else /* HAVE_LIBBFD_SUPPORT */ > > static int filename_split(char *filename, unsigned int *line_nr) > @@ -249,7 +327,8 @@ static int filename_split(char *filename, unsigned int *line_nr) > static int addr2line(const char *dso_name, u64 addr, > char **file, unsigned int *line_nr, > struct dso *dso __maybe_unused, > - bool unwind_inlines __maybe_unused) > + bool unwind_inlines __maybe_unused, > + struct inline_node *node __maybe_unused) > { > FILE *fp; > char cmd[PATH_MAX]; > @@ -288,6 +367,57 @@ void dso__free_a2l(struct dso *dso __maybe_unused) > { > } > > +static struct inline_node *addr2inlines(const char *dso_name, u64 addr, > + struct dso *dso __maybe_unused) > +{ > + FILE *fp; > + char cmd[PATH_MAX]; > + struct inline_node *node; > + char *filename = NULL; > + size_t len; > + unsigned int line_nr = 0; > + > + scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64, > + dso_name, addr); > + > + fp = popen(cmd, "r"); > + if (fp == NULL) { > + pr_err("popen failed for %s\n", dso_name); > + return NULL; > + } > + > + node = zalloc(sizeof(*node)); > + if (node == NULL) { > + perror("not enough memory for the inline node"); > + goto out; > + } > + > + INIT_LIST_HEAD(&node->val); > + node->addr = addr; > + > + while (getline(&filename, &len, fp) != -1) { > + if (filename_split(filename, &line_nr) != 1) { > + free(filename); > + goto out; > + } > + > + if (inline_list__append(filename, NULL, line_nr, node) != 0) > + goto out; > + > + filename = NULL; > + } > + > +out: > + pclose(fp); > + > + if (list_empty(&node->val)) { > + inline_node__delete(node); > + return NULL; > + } > + > + return node; > +} > + > #endif /* HAVE_LIBBFD_SUPPORT */ > > /* > @@ -311,7 +441,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, > if (dso_name == NULL) > goto out; > > - if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines)) > + if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL)) > goto out; > > if (asprintf(&srcline, "%s:%u", > @@ -351,3 +481,32 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, > { > return __get_srcline(dso, addr, sym, show_sym, false); > } > + > +struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr) > +{ > + const char *dso_name; > + > + dso_name = dso__name(dso); > + if (dso_name == NULL) > + return NULL; > + > + return addr2inlines(dso_name, addr, dso); > +} > + > +void inline_node__delete(struct inline_node *node) > +{ > + struct inline_list *ilist, *tmp; > + > + list_for_each_entry_safe(ilist, tmp, &node->val, list) { > + list_del_init(&ilist->list); > + if (ilist->filename != NULL) > + free(ilist->filename); > + > + if (ilist->funcname != NULL) > + free(ilist->funcname); > + > + free(ilist); > + } > + > + free(node); > +} > diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c > index 4e59dde..3a1dda3 100644 > --- a/tools/perf/util/symbol-elf.c > +++ b/tools/perf/util/symbol-elf.c > @@ -390,6 +390,11 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map * > return 0; > } > > +char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name) > +{ > + return demangle_sym(dso, kmodule, elf_name); > +} > + > /* > * Align offset to 4 bytes as needed for note name and descriptor data. > */ > diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h > index 6c358b7..8adf045 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, > int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, > struct map *map); > > +char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name); > + > void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel); > void symbols__insert(struct rb_root *symbols, struct symbol *sym); > void symbols__fixup_duplicate(struct rb_root *symbols); > diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h > index b2cfa47..cc0700d 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); > int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); > > int unit_number__scnprintf(char *buf, size_t size, u64 n); > + > +struct inline_list { > + char *filename; > + char *funcname; > + unsigned int line_nr; > + struct list_head list; > +}; > + > +struct inline_node { > + u64 addr; > + struct list_head val; > +}; > + > +struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr); > +void inline_node__delete(struct inline_node *node); > + > #endif /* GIT_COMPAT_UTIL_H */ > -- > 2.7.4