summaryrefslogtreecommitdiff
path: root/tools/perf/util/maps.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/maps.c')
-rw-r--r--tools/perf/util/maps.c317
1 files changed, 195 insertions, 122 deletions
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index 37bd5b40000d..1aeb1db58fe5 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -10,17 +10,15 @@
#include "ui/ui.h"
#include "unwind.h"
-static void __maps__insert(struct maps *maps, struct map *map);
-
static void maps__init(struct maps *maps, struct machine *machine)
{
- maps->entries = RB_ROOT;
- init_rwsem(&maps->lock);
- maps->machine = machine;
- maps->last_search_by_name = NULL;
- maps->nr_maps = 0;
- maps->maps_by_name = NULL;
- refcount_set(&maps->refcnt, 1);
+ refcount_set(maps__refcnt(maps), 1);
+ init_rwsem(maps__lock(maps));
+ RC_CHK_ACCESS(maps)->entries = RB_ROOT;
+ RC_CHK_ACCESS(maps)->machine = machine;
+ RC_CHK_ACCESS(maps)->last_search_by_name = NULL;
+ RC_CHK_ACCESS(maps)->nr_maps = 0;
+ RC_CHK_ACCESS(maps)->maps_by_name = NULL;
}
static void __maps__free_maps_by_name(struct maps *maps)
@@ -28,17 +26,54 @@ static void __maps__free_maps_by_name(struct maps *maps)
/*
* Free everything to try to do it from the rbtree in the next search
*/
- zfree(&maps->maps_by_name);
- maps->nr_maps_allocated = 0;
+ for (unsigned int i = 0; i < maps__nr_maps(maps); i++)
+ map__put(maps__maps_by_name(maps)[i]);
+
+ zfree(&RC_CHK_ACCESS(maps)->maps_by_name);
+ RC_CHK_ACCESS(maps)->nr_maps_allocated = 0;
}
-void maps__insert(struct maps *maps, struct map *map)
+static int __maps__insert(struct maps *maps, struct map *map)
{
- down_write(&maps->lock);
- __maps__insert(maps, map);
- ++maps->nr_maps;
+ struct rb_node **p = &maps__entries(maps)->rb_node;
+ struct rb_node *parent = NULL;
+ const u64 ip = map__start(map);
+ struct map_rb_node *m, *new_rb_node;
+
+ new_rb_node = malloc(sizeof(*new_rb_node));
+ if (!new_rb_node)
+ return -ENOMEM;
+
+ RB_CLEAR_NODE(&new_rb_node->rb_node);
+ new_rb_node->map = map__get(map);
+
+ while (*p != NULL) {
+ parent = *p;
+ m = rb_entry(parent, struct map_rb_node, rb_node);
+ if (ip < map__start(m->map))
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
- if (map->dso && map->dso->kernel) {
+ rb_link_node(&new_rb_node->rb_node, parent, p);
+ rb_insert_color(&new_rb_node->rb_node, maps__entries(maps));
+ return 0;
+}
+
+int maps__insert(struct maps *maps, struct map *map)
+{
+ int err;
+ const struct dso *dso = map__dso(map);
+
+ down_write(maps__lock(maps));
+ err = __maps__insert(maps, map);
+ if (err)
+ goto out;
+
+ ++RC_CHK_ACCESS(maps)->nr_maps;
+
+ if (dso && dso->kernel) {
struct kmap *kmap = map__kmap(map);
if (kmap)
@@ -52,60 +87,72 @@ void maps__insert(struct maps *maps, struct map *map)
* If we already performed some search by name, then we need to add the just
* inserted map and resort.
*/
- if (maps->maps_by_name) {
- if (maps->nr_maps > maps->nr_maps_allocated) {
- int nr_allocate = maps->nr_maps * 2;
- struct map **maps_by_name = realloc(maps->maps_by_name, nr_allocate * sizeof(map));
+ if (maps__maps_by_name(maps)) {
+ if (maps__nr_maps(maps) > RC_CHK_ACCESS(maps)->nr_maps_allocated) {
+ int nr_allocate = maps__nr_maps(maps) * 2;
+ struct map **maps_by_name = realloc(maps__maps_by_name(maps),
+ nr_allocate * sizeof(map));
if (maps_by_name == NULL) {
__maps__free_maps_by_name(maps);
- up_write(&maps->lock);
- return;
+ err = -ENOMEM;
+ goto out;
}
- maps->maps_by_name = maps_by_name;
- maps->nr_maps_allocated = nr_allocate;
+ RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name;
+ RC_CHK_ACCESS(maps)->nr_maps_allocated = nr_allocate;
}
- maps->maps_by_name[maps->nr_maps - 1] = map;
+ maps__maps_by_name(maps)[maps__nr_maps(maps) - 1] = map__get(map);
__maps__sort_by_name(maps);
}
- up_write(&maps->lock);
+ out:
+ up_write(maps__lock(maps));
+ return err;
}
-static void __maps__remove(struct maps *maps, struct map *map)
+static void __maps__remove(struct maps *maps, struct map_rb_node *rb_node)
{
- rb_erase_init(&map->rb_node, &maps->entries);
- map__put(map);
+ rb_erase_init(&rb_node->rb_node, maps__entries(maps));
+ map__put(rb_node->map);
+ free(rb_node);
}
void maps__remove(struct maps *maps, struct map *map)
{
- down_write(&maps->lock);
- if (maps->last_search_by_name == map)
- maps->last_search_by_name = NULL;
+ struct map_rb_node *rb_node;
- __maps__remove(maps, map);
- --maps->nr_maps;
- if (maps->maps_by_name)
+ down_write(maps__lock(maps));
+ if (RC_CHK_ACCESS(maps)->last_search_by_name == map)
+ RC_CHK_ACCESS(maps)->last_search_by_name = NULL;
+
+ rb_node = maps__find_node(maps, map);
+ assert(rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map));
+ __maps__remove(maps, rb_node);
+ if (maps__maps_by_name(maps))
__maps__free_maps_by_name(maps);
- up_write(&maps->lock);
+ --RC_CHK_ACCESS(maps)->nr_maps;
+ up_write(maps__lock(maps));
}
static void __maps__purge(struct maps *maps)
{
- struct map *pos, *next;
+ struct map_rb_node *pos, *next;
+
+ if (maps__maps_by_name(maps))
+ __maps__free_maps_by_name(maps);
maps__for_each_entry_safe(maps, pos, next) {
- rb_erase_init(&pos->rb_node, &maps->entries);
- map__put(pos);
+ rb_erase_init(&pos->rb_node, maps__entries(maps));
+ map__put(pos->map);
+ free(pos);
}
}
static void maps__exit(struct maps *maps)
{
- down_write(&maps->lock);
+ down_write(maps__lock(maps));
__maps__purge(maps);
- up_write(&maps->lock);
+ up_write(maps__lock(maps));
}
bool maps__empty(struct maps *maps)
@@ -115,25 +162,38 @@ bool maps__empty(struct maps *maps)
struct maps *maps__new(struct machine *machine)
{
- struct maps *maps = zalloc(sizeof(*maps));
+ struct maps *result;
+ RC_STRUCT(maps) *maps = zalloc(sizeof(*maps));
- if (maps != NULL)
- maps__init(maps, machine);
+ if (ADD_RC_CHK(result, maps))
+ maps__init(result, machine);
- return maps;
+ return result;
}
void maps__delete(struct maps *maps)
{
maps__exit(maps);
unwind__finish_access(maps);
- free(maps);
+ RC_CHK_FREE(maps);
+}
+
+struct maps *maps__get(struct maps *maps)
+{
+ struct maps *result;
+
+ if (RC_CHK_GET(result, maps))
+ refcount_inc(maps__refcnt(maps));
+
+ return result;
}
void maps__put(struct maps *maps)
{
- if (maps && refcount_dec_and_test(&maps->refcnt))
+ if (maps && refcount_dec_and_test(maps__refcnt(maps)))
maps__delete(maps);
+ else
+ RC_CHK_PUT(maps);
}
struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)
@@ -144,7 +204,7 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)
if (map != NULL && map__load(map) >= 0) {
if (mapp != NULL)
*mapp = map;
- return map__find_symbol(map, map->map_ip(map, addr));
+ return map__find_symbol(map, map__map_ip(map, addr));
}
return NULL;
@@ -153,33 +213,33 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)
struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp)
{
struct symbol *sym;
- struct map *pos;
+ struct map_rb_node *pos;
- down_read(&maps->lock);
+ down_read(maps__lock(maps));
maps__for_each_entry(maps, pos) {
- sym = map__find_symbol_by_name(pos, name);
+ sym = map__find_symbol_by_name(pos->map, name);
if (sym == NULL)
continue;
- if (!map__contains_symbol(pos, sym)) {
+ if (!map__contains_symbol(pos->map, sym)) {
sym = NULL;
continue;
}
if (mapp != NULL)
- *mapp = pos;
+ *mapp = pos->map;
goto out;
}
sym = NULL;
out:
- up_read(&maps->lock);
+ up_read(maps__lock(maps));
return sym;
}
int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
{
- if (ams->addr < ams->ms.map->start || ams->addr >= ams->ms.map->end) {
+ if (ams->addr < map__start(ams->ms.map) || ams->addr >= map__end(ams->ms.map)) {
if (maps == NULL)
return -1;
ams->ms.map = maps__find(maps, ams->addr);
@@ -187,7 +247,7 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
return -1;
}
- ams->al_addr = ams->ms.map->map_ip(ams->ms.map, ams->addr);
+ ams->al_addr = map__map_ip(ams->ms.map, ams->addr);
ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr);
return ams->ms.sym ? 0 : -1;
@@ -196,20 +256,20 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
size_t maps__fprintf(struct maps *maps, FILE *fp)
{
size_t printed = 0;
- struct map *pos;
+ struct map_rb_node *pos;
- down_read(&maps->lock);
+ down_read(maps__lock(maps));
maps__for_each_entry(maps, pos) {
printed += fprintf(fp, "Map:");
- printed += map__fprintf(pos, fp);
+ printed += map__fprintf(pos->map, fp);
if (verbose > 2) {
- printed += dso__fprintf(pos->dso, fp);
+ printed += dso__fprintf(map__dso(pos->map), fp);
printed += fprintf(fp, "--\n");
}
}
- up_read(&maps->lock);
+ up_read(maps__lock(maps));
return printed;
}
@@ -220,9 +280,9 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
struct rb_node *next, *first;
int err = 0;
- down_write(&maps->lock);
+ down_write(maps__lock(maps));
- root = &maps->entries;
+ root = maps__entries(maps);
/*
* Find first map where end > map->start.
@@ -231,11 +291,11 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
next = root->rb_node;
first = NULL;
while (next) {
- struct map *pos = rb_entry(next, struct map, rb_node);
+ struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node);
- if (pos->end > map->start) {
+ if (map__end(pos->map) > map__start(map)) {
first = next;
- if (pos->start <= map->start)
+ if (map__start(pos->map) <= map__start(map))
break;
next = next->rb_left;
} else
@@ -243,26 +303,26 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
}
next = first;
- while (next) {
- struct map *pos = rb_entry(next, struct map, rb_node);
+ while (next && !err) {
+ struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node);
next = rb_next(&pos->rb_node);
/*
* Stop if current map starts after map->end.
* Maps are ordered by start: next will not overlap for sure.
*/
- if (pos->start >= map->end)
+ if (map__start(pos->map) >= map__end(map))
break;
if (verbose >= 2) {
if (use_browser) {
pr_debug("overlapping maps in %s (disable tui for more info)\n",
- map->dso->name);
+ map__dso(map)->name);
} else {
fputs("overlapping maps:\n", fp);
map__fprintf(map, fp);
- map__fprintf(pos, fp);
+ map__fprintf(pos->map, fp);
}
}
@@ -271,47 +331,51 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
* Now check if we need to create new maps for areas not
* overlapped by the new map:
*/
- if (map->start > pos->start) {
- struct map *before = map__clone(pos);
+ if (map__start(map) > map__start(pos->map)) {
+ struct map *before = map__clone(pos->map);
if (before == NULL) {
err = -ENOMEM;
goto put_map;
}
- before->end = map->start;
- __maps__insert(maps, before);
+ map__set_end(before, map__start(map));
+ err = __maps__insert(maps, before);
+ if (err) {
+ map__put(before);
+ goto put_map;
+ }
+
if (verbose >= 2 && !use_browser)
map__fprintf(before, fp);
map__put(before);
}
- if (map->end < pos->end) {
- struct map *after = map__clone(pos);
+ if (map__end(map) < map__end(pos->map)) {
+ struct map *after = map__clone(pos->map);
if (after == NULL) {
err = -ENOMEM;
goto put_map;
}
- after->start = map->end;
- after->pgoff += map->end - pos->start;
- assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end));
- __maps__insert(maps, after);
+ map__set_start(after, map__end(map));
+ map__add_pgoff(after, map__end(map) - map__start(pos->map));
+ assert(map__map_ip(pos->map, map__end(map)) ==
+ map__map_ip(after, map__end(map)));
+ err = __maps__insert(maps, after);
+ if (err) {
+ map__put(after);
+ goto put_map;
+ }
if (verbose >= 2 && !use_browser)
map__fprintf(after, fp);
map__put(after);
}
put_map:
- map__put(pos);
-
- if (err)
- goto out;
+ map__put(pos->map);
}
-
- err = 0;
-out:
- up_write(&maps->lock);
+ up_write(maps__lock(maps));
return err;
}
@@ -322,12 +386,12 @@ int maps__clone(struct thread *thread, struct maps *parent)
{
struct maps *maps = thread->maps;
int err;
- struct map *map;
+ struct map_rb_node *rb_node;
- down_read(&parent->lock);
+ down_read(maps__lock(parent));
- maps__for_each_entry(parent, map) {
- struct map *new = map__clone(map);
+ maps__for_each_entry(parent, rb_node) {
+ struct map *new = map__clone(rb_node->map);
if (new == NULL) {
err = -ENOMEM;
@@ -338,50 +402,44 @@ int maps__clone(struct thread *thread, struct maps *parent)
if (err)
goto out_unlock;
- maps__insert(maps, new);
+ err = maps__insert(maps, new);
+ if (err)
+ goto out_unlock;
+
map__put(new);
}
err = 0;
out_unlock:
- up_read(&parent->lock);
+ up_read(maps__lock(parent));
return err;
}
-static void __maps__insert(struct maps *maps, struct map *map)
+struct map_rb_node *maps__find_node(struct maps *maps, struct map *map)
{
- struct rb_node **p = &maps->entries.rb_node;
- struct rb_node *parent = NULL;
- const u64 ip = map->start;
- struct map *m;
+ struct map_rb_node *rb_node;
- while (*p != NULL) {
- parent = *p;
- m = rb_entry(parent, struct map, rb_node);
- if (ip < m->start)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
+ maps__for_each_entry(maps, rb_node) {
+ if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map))
+ return rb_node;
}
-
- rb_link_node(&map->rb_node, parent, p);
- rb_insert_color(&map->rb_node, &maps->entries);
- map__get(map);
+ return NULL;
}
struct map *maps__find(struct maps *maps, u64 ip)
{
struct rb_node *p;
- struct map *m;
+ struct map_rb_node *m;
+
- down_read(&maps->lock);
+ down_read(maps__lock(maps));
- p = maps->entries.rb_node;
+ p = maps__entries(maps)->rb_node;
while (p != NULL) {
- m = rb_entry(p, struct map, rb_node);
- if (ip < m->start)
+ m = rb_entry(p, struct map_rb_node, rb_node);
+ if (ip < map__start(m->map))
p = p->rb_left;
- else if (ip >= m->end)
+ else if (ip >= map__end(m->map))
p = p->rb_right;
else
goto out;
@@ -389,15 +447,30 @@ struct map *maps__find(struct maps *maps, u64 ip)
m = NULL;
out:
- up_read(&maps->lock);
- return m;
+ up_read(maps__lock(maps));
+ return m ? m->map : NULL;
}
-struct map *maps__first(struct maps *maps)
+struct map_rb_node *maps__first(struct maps *maps)
{
- struct rb_node *first = rb_first(&maps->entries);
+ struct rb_node *first = rb_first(maps__entries(maps));
if (first)
- return rb_entry(first, struct map, rb_node);
+ return rb_entry(first, struct map_rb_node, rb_node);
return NULL;
}
+
+struct map_rb_node *map_rb_node__next(struct map_rb_node *node)
+{
+ struct rb_node *next;
+
+ if (!node)
+ return NULL;
+
+ next = rb_next(&node->rb_node);
+
+ if (!next)
+ return NULL;
+
+ return rb_entry(next, struct map_rb_node, rb_node);
+}