Merge branch 'linus' into perf/core, to fix conflicts
[linux-2.6-microblaze.git] / tools / perf / util / srcline.c
index f202fc7..d19f05c 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -10,7 +11,7 @@
 #include "util/debug.h"
 #include "util/callchain.h"
 #include "srcline.h"
-
+#include "string2.h"
 #include "symbol.h"
 
 bool srcline_full_filename;
@@ -77,6 +78,41 @@ static char *srcline_from_fileline(const char *file, unsigned int line)
        return srcline;
 }
 
+static struct symbol *new_inline_sym(struct dso *dso,
+                                    struct symbol *base_sym,
+                                    const char *funcname)
+{
+       struct symbol *inline_sym;
+       char *demangled = NULL;
+
+       if (dso) {
+               demangled = dso__demangle_sym(dso, 0, funcname);
+               if (demangled)
+                       funcname = demangled;
+       }
+
+       if (base_sym && strcmp(funcname, base_sym->name) == 0) {
+               /* reuse the real, existing symbol */
+               inline_sym = base_sym;
+               /* ensure that we don't alias an inlined symbol, which could
+                * lead to double frees in inline_node__delete
+                */
+               assert(!base_sym->inlined);
+       } else {
+               /* create a fake symbol for the inline frame */
+               inline_sym = symbol__new(base_sym ? base_sym->start : 0,
+                                        base_sym ? base_sym->end : 0,
+                                        base_sym ? base_sym->binding : 0,
+                                        funcname);
+               if (inline_sym)
+                       inline_sym->inlined = 1;
+       }
+
+       free(demangled);
+
+       return inline_sym;
+}
+
 #ifdef HAVE_LIBBFD_SUPPORT
 
 /*
@@ -219,41 +255,6 @@ static void addr2line_cleanup(struct a2l_data *a2l)
 
 #define MAX_INLINE_NEST 1024
 
-static struct symbol *new_inline_sym(struct dso *dso,
-                                    struct symbol *base_sym,
-                                    const char *funcname)
-{
-       struct symbol *inline_sym;
-       char *demangled = NULL;
-
-       if (dso) {
-               demangled = dso__demangle_sym(dso, 0, funcname);
-               if (demangled)
-                       funcname = demangled;
-       }
-
-       if (base_sym && strcmp(funcname, base_sym->name) == 0) {
-               /* reuse the real, existing symbol */
-               inline_sym = base_sym;
-               /* ensure that we don't alias an inlined symbol, which could
-                * lead to double frees in inline_node__delete
-                */
-               assert(!base_sym->inlined);
-       } else {
-               /* create a fake symbol for the inline frame */
-               inline_sym = symbol__new(base_sym ? base_sym->start : 0,
-                                        base_sym ? base_sym->end : 0,
-                                        base_sym ? base_sym->binding : 0,
-                                        funcname);
-               if (inline_sym)
-                       inline_sym->inlined = 1;
-       }
-
-       free(demangled);
-
-       return inline_sym;
-}
-
 static int inline_list__append_dso_a2l(struct dso *dso,
                                       struct inline_node *node,
                                       struct symbol *sym)
@@ -353,17 +354,8 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
        INIT_LIST_HEAD(&node->val);
        node->addr = addr;
 
-       if (!addr2line(dso_name, addr, NULL, NULL, dso, TRUE, node, sym))
-               goto out_free_inline_node;
-
-       if (list_empty(&node->val))
-               goto out_free_inline_node;
-
+       addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym);
        return node;
-
-out_free_inline_node:
-       inline_node__delete(node);
-       return NULL;
 }
 
 #else /* HAVE_LIBBFD_SUPPORT */
@@ -441,10 +433,11 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
        char cmd[PATH_MAX];
        struct inline_node *node;
        char *filename = NULL;
-       size_t len;
+       char *funcname = NULL;
+       size_t filelen, funclen;
        unsigned int line_nr = 0;
 
-       scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
+       scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i -f %016"PRIx64,
                  dso_name, addr);
 
        fp = popen(cmd, "r");
@@ -462,28 +455,34 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
        INIT_LIST_HEAD(&node->val);
        node->addr = addr;
 
-       while (getline(&filename, &len, fp) != -1) {
+       /* addr2line -f generates two lines for each inlined functions */
+       while (getline(&funcname, &funclen, fp) != -1) {
                char *srcline;
+               struct symbol *inline_sym;
 
-               if (filename_split(filename, &line_nr) != 1) {
-                       free(filename);
+               rtrim(funcname);
+
+               if (getline(&filename, &filelen, fp) == -1)
                        goto out;
-               }
 
-               srcline = srcline_from_fileline(filename, line_nr);
-               if (inline_list__append(sym, srcline, node) != 0)
+               if (filename_split(filename, &line_nr) != 1)
                        goto out;
 
-               filename = NULL;
+               srcline = srcline_from_fileline(filename, line_nr);
+               inline_sym = new_inline_sym(dso, sym, funcname);
+
+               if (inline_list__append(inline_sym, srcline, node) != 0) {
+                       free(srcline);
+                       if (inline_sym && inline_sym->inlined)
+                               symbol__delete(inline_sym);
+                       goto out;
+               }
        }
 
 out:
        pclose(fp);
-
-       if (list_empty(&node->val)) {
-               inline_node__delete(node);
-               return NULL;
-       }
+       free(filename);
+       free(funcname);
 
        return node;
 }
@@ -556,6 +555,72 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
        return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
 }
 
+struct srcline_node {
+       u64                     addr;
+       char                    *srcline;
+       struct rb_node          rb_node;
+};
+
+void srcline__tree_insert(struct rb_root *tree, u64 addr, char *srcline)
+{
+       struct rb_node **p = &tree->rb_node;
+       struct rb_node *parent = NULL;
+       struct srcline_node *i, *node;
+
+       node = zalloc(sizeof(struct srcline_node));
+       if (!node) {
+               perror("not enough memory for the srcline node");
+               return;
+       }
+
+       node->addr = addr;
+       node->srcline = srcline;
+
+       while (*p != NULL) {
+               parent = *p;
+               i = rb_entry(parent, struct srcline_node, rb_node);
+               if (addr < i->addr)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&node->rb_node, parent, p);
+       rb_insert_color(&node->rb_node, tree);
+}
+
+char *srcline__tree_find(struct rb_root *tree, u64 addr)
+{
+       struct rb_node *n = tree->rb_node;
+
+       while (n) {
+               struct srcline_node *i = rb_entry(n, struct srcline_node,
+                                                 rb_node);
+
+               if (addr < i->addr)
+                       n = n->rb_left;
+               else if (addr > i->addr)
+                       n = n->rb_right;
+               else
+                       return i->srcline;
+       }
+
+       return NULL;
+}
+
+void srcline__tree_delete(struct rb_root *tree)
+{
+       struct srcline_node *pos;
+       struct rb_node *next = rb_first(tree);
+
+       while (next) {
+               pos = rb_entry(next, struct srcline_node, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, tree);
+               free_srcline(pos->srcline);
+               zfree(&pos);
+       }
+}
+
 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
                                            struct symbol *sym)
 {
@@ -583,3 +648,54 @@ void inline_node__delete(struct inline_node *node)
 
        free(node);
 }
+
+void inlines__tree_insert(struct rb_root *tree, struct inline_node *inlines)
+{
+       struct rb_node **p = &tree->rb_node;
+       struct rb_node *parent = NULL;
+       const u64 addr = inlines->addr;
+       struct inline_node *i;
+
+       while (*p != NULL) {
+               parent = *p;
+               i = rb_entry(parent, struct inline_node, rb_node);
+               if (addr < i->addr)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&inlines->rb_node, parent, p);
+       rb_insert_color(&inlines->rb_node, tree);
+}
+
+struct inline_node *inlines__tree_find(struct rb_root *tree, u64 addr)
+{
+       struct rb_node *n = tree->rb_node;
+
+       while (n) {
+               struct inline_node *i = rb_entry(n, struct inline_node,
+                                                rb_node);
+
+               if (addr < i->addr)
+                       n = n->rb_left;
+               else if (addr > i->addr)
+                       n = n->rb_right;
+               else
+                       return i;
+       }
+
+       return NULL;
+}
+
+void inlines__tree_delete(struct rb_root *tree)
+{
+       struct inline_node *pos;
+       struct rb_node *next = rb_first(tree);
+
+       while (next) {
+               pos = rb_entry(next, struct inline_node, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, tree);
+               inline_node__delete(pos);
+       }
+}