Merge tag 'mac80211-next-for-john-2014-11-04' of git://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / tools / perf / util / dso.c
index 90d02c6..0247acf 100644 (file)
@@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 {
        char build_id_hex[BUILD_ID_SIZE * 2 + 1];
        int ret = 0;
+       size_t len;
 
        switch (type) {
        case DSO_BINARY_TYPE__DEBUGLINK: {
@@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso,
                break;
 
        case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s.debug",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s.debug", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
        {
                const char *last_slash;
-               size_t len;
                size_t dir_size;
 
                last_slash = dso->long_name + dso->long_name_len;
                while (last_slash != dso->long_name && *last_slash != '/')
                        last_slash--;
 
-               len = scnprintf(filename, size, "%s", symbol_conf.symfs);
+               len = __symbol__join_symfs(filename, size, "");
                dir_size = last_slash - dso->long_name + 2;
                if (dir_size > (size - len)) {
                        ret = -1;
@@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso,
                build_id__sprintf(dso->build_id,
                                  sizeof(dso->build_id),
                                  build_id_hex);
-               snprintf(filename, size,
-                        "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
-                        symbol_conf.symfs, build_id_hex, build_id_hex + 2);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
+               snprintf(filename + len, size - len, "%.2s/%s.debug",
+                        build_id_hex, build_id_hex + 2);
                break;
 
        case DSO_BINARY_TYPE__VMLINUX:
        case DSO_BINARY_TYPE__GUEST_VMLINUX:
        case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
-               snprintf(filename, size, "%s%s",
-                        symbol_conf.symfs, dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__GUEST_KMODULE:
-               snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
-                        root_dir, dso->long_name);
+               path__join3(filename, size, symbol_conf.symfs,
+                           root_dir, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
-               snprintf(filename, size, "%s%s", symbol_conf.symfs,
-                        dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__KCORE:
@@ -164,13 +162,15 @@ static void close_first_dso(void);
 static int do_open(char *name)
 {
        int fd;
+       char sbuf[STRERR_BUFSIZE];
 
        do {
                fd = open(name, O_RDONLY);
                if (fd >= 0)
                        return fd;
 
-               pr_debug("dso open failed, mmap: %s\n", strerror(errno));
+               pr_debug("dso open failed, mmap: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                if (!dso__data_open_cnt || errno != EMFILE)
                        break;
 
@@ -532,10 +532,12 @@ static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
 static int data_file_size(struct dso *dso)
 {
        struct stat st;
+       char sbuf[STRERR_BUFSIZE];
 
        if (!dso->data.file_size) {
                if (fstat(dso->data.fd, &st)) {
-                       pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
+                       pr_err("dso mmap failed, fstat: %s\n",
+                               strerror_r(errno, sbuf, sizeof(sbuf)));
                        return -1;
                }
                dso->data.file_size = st.st_size;
@@ -651,6 +653,65 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
        return dso;
 }
 
+/*
+ * Find a matching entry and/or link current entry to RB tree.
+ * Either one of the dso or name parameter must be non-NULL or the
+ * function will not work.
+ */
+static struct dso *dso__findlink_by_longname(struct rb_root *root,
+                                            struct dso *dso, const char *name)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node  *parent = NULL;
+
+       if (!name)
+               name = dso->long_name;
+       /*
+        * Find node with the matching name
+        */
+       while (*p) {
+               struct dso *this = rb_entry(*p, struct dso, rb_node);
+               int rc = strcmp(name, this->long_name);
+
+               parent = *p;
+               if (rc == 0) {
+                       /*
+                        * In case the new DSO is a duplicate of an existing
+                        * one, print an one-time warning & put the new entry
+                        * at the end of the list of duplicates.
+                        */
+                       if (!dso || (dso == this))
+                               return this;    /* Find matching dso */
+                       /*
+                        * The core kernel DSOs may have duplicated long name.
+                        * In this case, the short name should be different.
+                        * Comparing the short names to differentiate the DSOs.
+                        */
+                       rc = strcmp(dso->short_name, this->short_name);
+                       if (rc == 0) {
+                               pr_err("Duplicated dso name: %s\n", name);
+                               return NULL;
+                       }
+               }
+               if (rc < 0)
+                       p = &parent->rb_left;
+               else
+                       p = &parent->rb_right;
+       }
+       if (dso) {
+               /* Add new node and rebalance tree */
+               rb_link_node(&dso->rb_node, parent, p);
+               rb_insert_color(&dso->rb_node, root);
+       }
+       return NULL;
+}
+
+static inline struct dso *
+dso__find_by_longname(const struct rb_root *root, const char *name)
+{
+       return dso__findlink_by_longname((struct rb_root *)root, NULL, name);
+}
+
 void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
 {
        if (name == NULL)
@@ -753,6 +814,7 @@ struct dso *dso__new(const char *name)
                dso->a2l_fails = 1;
                dso->kernel = DSO_TYPE_USER;
                dso->needs_swap = DSO_SWAP__UNSET;
+               RB_CLEAR_NODE(&dso->rb_node);
                INIT_LIST_HEAD(&dso->node);
                INIT_LIST_HEAD(&dso->data.open_entry);
        }
@@ -763,6 +825,10 @@ struct dso *dso__new(const char *name)
 void dso__delete(struct dso *dso)
 {
        int i;
+
+       if (!RB_EMPTY_NODE(&dso->rb_node))
+               pr_err("DSO %s is still in rbtree when being deleted!\n",
+                      dso->long_name);
        for (i = 0; i < MAP__NR_TYPES; ++i)
                symbols__delete(&dso->symbols[i]);
 
@@ -849,35 +915,34 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
        return have_build_id;
 }
 
-void dsos__add(struct list_head *head, struct dso *dso)
+void dsos__add(struct dsos *dsos, struct dso *dso)
 {
-       list_add_tail(&dso->node, head);
+       list_add_tail(&dso->node, &dsos->head);
+       dso__findlink_by_longname(&dsos->root, dso, NULL);
 }
 
-struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short)
+struct dso *dsos__find(const struct dsos *dsos, const char *name,
+                      bool cmp_short)
 {
        struct dso *pos;
 
        if (cmp_short) {
-               list_for_each_entry(pos, head, node)
+               list_for_each_entry(pos, &dsos->head, node)
                        if (strcmp(pos->short_name, name) == 0)
                                return pos;
                return NULL;
        }
-       list_for_each_entry(pos, head, node)
-               if (strcmp(pos->long_name, name) == 0)
-                       return pos;
-       return NULL;
+       return dso__find_by_longname(&dsos->root, name);
 }
 
-struct dso *__dsos__findnew(struct list_head *head, const char *name)
+struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
 {
-       struct dso *dso = dsos__find(head, name, false);
+       struct dso *dso = dsos__find(dsos, name, false);
 
        if (!dso) {
                dso = dso__new(name);
                if (dso != NULL) {
-                       dsos__add(head, dso);
+                       dsos__add(dsos, dso);
                        dso__set_basename(dso);
                }
        }