#include "symbol.h"
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "map.h"
#include "thread.h"
#include "strlist.h"
#include "vdso.h"
const char *map_type__name[MAP__NR_TYPES] = {
[MAP__FUNCTION] = "Functions",
[MAP__VARIABLE] = "Variables",
};
static inline int is_anon_memory(const char *filename)
{
return strcmp(filename, "//anon") == 0;
}
static inline int is_no_dso_memory(const char *filename)
{
return !strcmp(filename, "[stack]") ||
!strcmp(filename, "[heap]");
}
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);
self->groups = NULL;
self->referenced = false;
self->erange_warned = false;
}
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
u64 pgoff, u32 pid, char *filename,
enum map_type type)
{
struct map *self = malloc(sizeof(*self));
if (self != NULL) {
char newfilename[PATH_MAX];
struct dso *dso;
int anon, no_dso, vdso;
anon = is_anon_memory(filename);
vdso = is_vdso_map(filename);
no_dso = is_no_dso_memory(filename);
if (anon) {
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
filename = newfilename;
}
if (vdso) {
pgoff = 0;
dso = vdso__dso_findnew(dsos__list);
} else
dso = __dsos__findnew(dsos__list, filename);
if (dso == NULL)
goto out_delete;
map__init(self, type, start, start + len, pgoff, dso);
if (anon || no_dso) {
self->map_ip = self->unmap_ip = identity__map_ip;
/*
* Set memory without DSO as loaded. All map__find_*
* functions still return NULL, and we avoid the
* unnecessary map__load warning.
*/
if (no_dso)
dso__set_loaded(dso, self->type);
}
}
return self;
out_delete:
free(self);
return NULL;
}
/*
* Constructor variant for modules (where we know from /proc/modules where
* they are loaded) and for vmlinux, where only after we load all the
* symbols we'll know where it starts and ends.
*/
struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
{
struct map *map = calloc(1, (sizeof(*map) +
(dso->kernel ? sizeof(struct kmap) : 0)));
if (map != NULL) {
/*
* ->end will be filled after we load all the symbols
*/
map__init(map, type, start, 0, 0, dso);
}
return map;
}
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)"
int map__load(struct map *self, symbol_filter_t filter)
{
const char *name = self->dso->long_name;
int nr;
if (dso__loaded(self->dso, self->type))
return 0;
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",
name, sbuild_id);
} else
pr_warning("Failed to open %s", name);
pr_warning(", continuing without symbols\n");
return -1;
} else if (nr == 0) {
#ifdef LIBELF_SUPPORT
const size_t len = strlen(name);
const