aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/map.c')
-rw-r--r--tools/perf/util/map.c99
1 files changed, 89 insertions, 10 deletions
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 804e02382739..69f94fe9db20 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include "debug.h"
static inline int is_anon_memory(const char *filename)
{
@@ -19,13 +20,28 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
return n;
}
- struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
+void map__init(struct map *self, enum map_type type,
+ u64 start, u64 end, u64 pgoff, struct dso *dso)
+{
+ self->type = type;
+ self->start = start;
+ self->end = end;
+ self->pgoff = pgoff;
+ self->dso = dso;
+ self->map_ip = map__map_ip;
+ self->unmap_ip = map__unmap_ip;
+ RB_CLEAR_NODE(&self->rb_node);
+}
+
+struct map *map__new(struct mmap_event *event, enum map_type type,
+ char *cwd, int cwdlen)
{
struct map *self = malloc(sizeof(*self));
if (self != NULL) {
const char *filename = event->filename;
char newfilename[PATH_MAX];
+ struct dso *dso;
int anon;
if (cwd) {
@@ -45,18 +61,15 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
filename = newfilename;
}
- self->start = event->start;
- self->end = event->start + event->len;
- self->pgoff = event->pgoff;
-
- self->dso = dsos__findnew(filename);
- if (self->dso == NULL)
+ dso = dsos__findnew(filename);
+ if (dso == NULL)
goto out_delete;
+ map__init(self, type, event->start, event->start + event->len,
+ event->pgoff, dso);
+
if (self->dso == vdso || anon)
- self->map_ip = vdso__map_ip;
- else
- self->map_ip = map__map_ip;
+ self->map_ip = self->unmap_ip = identity__map_ip;
}
return self;
out_delete:
@@ -64,6 +77,72 @@ out_delete:
return NULL;
}
+void map__delete(struct map *self)
+{
+ free(self);
+}
+
+void map__fixup_start(struct map *self)
+{
+ struct rb_root *symbols = &self->dso->symbols[self->type];
+ struct rb_node *nd = rb_first(symbols);
+ if (nd != NULL) {
+ struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ self->start = sym->start;
+ }
+}
+
+void map__fixup_end(struct map *self)
+{
+ struct rb_root *symbols = &self->dso->symbols[self->type];
+ struct rb_node *nd = rb_last(symbols);
+ if (nd != NULL) {
+ struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ self->end = sym->end;
+ }
+}
+
+#define DSO__DELETED "(deleted)"
+
+struct symbol *map__find_symbol(struct map *self, u64 addr,
+ symbol_filter_t filter)
+{
+ if (!dso__loaded(self->dso, self->type)) {
+ int nr = dso__load(self->dso, self, filter);
+
+ if (nr < 0) {
+ if (self->dso->has_build_id) {
+ char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+ build_id__sprintf(self->dso->build_id,
+ sizeof(self->dso->build_id),
+ sbuild_id);
+ pr_warning("%s with build id %s not found",
+ self->dso->long_name, sbuild_id);
+ } else
+ pr_warning("Failed to open %s",
+ self->dso->long_name);
+ pr_warning(", continuing without symbols\n");
+ return NULL;
+ } else if (nr == 0) {
+ const char *name = self->dso->long_name;
+ const size_t len = strlen(name);
+ const size_t real_len = len - sizeof(DSO__DELETED);
+
+ if (len > sizeof(DSO__DELETED) &&
+ strcmp(name + real_len + 1, DSO__DELETED) == 0) {
+ pr_warning("%.*s was updated, restart the long running apps that use it!\n",
+ (int)real_len, name);
+ } else {
+ pr_warning("no symbols found in %s, maybe install a debug package?\n", name);
+ }
+ return NULL;
+ }
+ }
+
+ return self->dso->find_symbol(self->dso, self->type, addr);
+}
+
struct map *map__clone(struct map *self)
{
struct map *map = malloc(sizeof(*self));