]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - tools/perf/util/symbol.c
perf tools: Protect accesses the map rbtrees with a rw lock
[mirror_ubuntu-artful-kernel.git] / tools / perf / util / symbol.c
index 201f6c4ca738ddffb46d5270a876cf96e8da9322..8aae8b6b1ceed72e695c3084eb531eed27bc9085 100644 (file)
@@ -85,8 +85,17 @@ static int prefix_underscores_count(const char *str)
        return tail - str;
 }
 
-#define SYMBOL_A 0
-#define SYMBOL_B 1
+int __weak arch__choose_best_symbol(struct symbol *syma,
+                                   struct symbol *symb __maybe_unused)
+{
+       /* Avoid "SyS" kernel syscall aliases */
+       if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
+               return SYMBOL_B;
+       if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
+               return SYMBOL_B;
+
+       return SYMBOL_A;
+}
 
 static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
 {
@@ -134,13 +143,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
        else if (na < nb)
                return SYMBOL_B;
 
-       /* Avoid "SyS" kernel syscall aliases */
-       if (na >= 3 && !strncmp(syma->name, "SyS", 3))
-               return SYMBOL_B;
-       if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10))
-               return SYMBOL_B;
-
-       return SYMBOL_A;
+       return arch__choose_best_symbol(syma, symb);
 }
 
 void symbols__fixup_duplicate(struct rb_root *symbols)
@@ -199,18 +202,18 @@ void symbols__fixup_end(struct rb_root *symbols)
 
 void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
 {
-       struct map *prev, *curr;
-       struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
+       struct maps *maps = &mg->maps[type];
+       struct map *next, *curr;
 
-       if (prevnd == NULL)
-               return;
+       pthread_rwlock_wrlock(&maps->lock);
 
-       curr = rb_entry(prevnd, struct map, rb_node);
+       curr = maps__first(maps);
+       if (curr == NULL)
+               goto out_unlock;
 
-       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
-               prev = curr;
-               curr = rb_entry(nd, struct map, rb_node);
-               prev->end = curr->start;
+       for (next = map__next(curr); next; next = map__next(curr)) {
+               curr->end = next->start;
+               curr = next;
        }
 
        /*
@@ -218,6 +221,9 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
         * last map final address.
         */
        curr->end = ~0ULL;
+
+out_unlock:
+       pthread_rwlock_unlock(&maps->lock);
 }
 
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
@@ -397,7 +403,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
                                            const char *name)
 {
        struct rb_node *n;
-       struct symbol_name_rb_node *s;
+       struct symbol_name_rb_node *s = NULL;
 
        if (symbols == NULL)
                return NULL;
@@ -408,7 +414,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
                int cmp;
 
                s = rb_entry(n, struct symbol_name_rb_node, rb_node);
-               cmp = strcmp(name, s->sym.name);
+               cmp = arch__compare_symbol_names(name, s->sym.name);
 
                if (cmp < 0)
                        n = n->rb_left;
@@ -426,7 +432,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
                struct symbol_name_rb_node *tmp;
 
                tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
-               if (strcmp(tmp->sym.name, s->sym.name))
+               if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
                        break;
 
                s = tmp;
@@ -1380,12 +1386,22 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
        bool kmod;
 
-       dso__set_loaded(dso, map->type);
+       pthread_mutex_lock(&dso->lock);
 
-       if (dso->kernel == DSO_TYPE_KERNEL)
-               return dso__load_kernel_sym(dso, map, filter);
-       else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
-               return dso__load_guest_kernel_sym(dso, map, filter);
+       /* check again under the dso->lock */
+       if (dso__loaded(dso, map->type)) {
+               ret = 1;
+               goto out;
+       }
+
+       if (dso->kernel) {
+               if (dso->kernel == DSO_TYPE_KERNEL)
+                       ret = dso__load_kernel_sym(dso, map, filter);
+               else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
+                       ret = dso__load_guest_kernel_sym(dso, map, filter);
+
+               goto out;
+       }
 
        if (map->groups && map->groups->machine)
                machine = map->groups->machine;
@@ -1398,18 +1414,18 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
                struct stat st;
 
                if (lstat(dso->name, &st) < 0)
-                       return -1;
+                       goto out;
 
                if (st.st_uid && (st.st_uid != geteuid())) {
                        pr_warning("File %s not owned by current user or root, "
                                "ignoring it.\n", dso->name);
-                       return -1;
+                       goto out;
                }
 
                ret = dso__load_perf_map(dso, map, filter);
                dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
                                             DSO_BINARY_TYPE__NOT_FOUND;
-               return ret;
+               goto out;
        }
 
        if (machine)
@@ -1417,7 +1433,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 
        name = malloc(PATH_MAX);
        if (!name)
-               return -1;
+               goto out;
 
        kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
                dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
@@ -1498,23 +1514,32 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 out_free:
        free(name);
        if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
-               return 0;
+               ret = 0;
+out:
+       dso__set_loaded(dso, map->type);
+       pthread_mutex_unlock(&dso->lock);
+
        return ret;
 }
 
 struct map *map_groups__find_by_name(struct map_groups *mg,
                                     enum map_type type, const char *name)
 {
-       struct rb_node *nd;
+       struct maps *maps = &mg->maps[type];
+       struct map *map;
 
-       for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
-               struct map *map = rb_entry(nd, struct map, rb_node);
+       pthread_rwlock_rdlock(&maps->lock);
 
+       for (map = maps__first(maps); map; map = map__next(map)) {
                if (map->dso && strcmp(map->dso->short_name, name) == 0)
-                       return map;
+                       goto out_unlock;
        }
 
-       return NULL;
+       map = NULL;
+
+out_unlock:
+       pthread_rwlock_unlock(&maps->lock);
+       return map;
 }
 
 int dso__load_vmlinux(struct dso *dso, struct map *map,
@@ -1802,6 +1827,7 @@ static void vmlinux_path__exit(void)
 {
        while (--vmlinux_path__nr_entries >= 0)
                zfree(&vmlinux_path[vmlinux_path__nr_entries]);
+       vmlinux_path__nr_entries = 0;
 
        zfree(&vmlinux_path);
 }