summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/dso.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/dso.c')
-rw-r--r--tools/perf/util/dso.c392
1 files changed, 115 insertions, 277 deletions
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index ebc9d46c15a7..91f21239608b 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -10,16 +10,18 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
-#include <libgen.h>
+#include <stdlib.h>
#include <bpf/libbpf.h>
#include "bpf-event.h"
#include "compress.h"
+#include "env.h"
#include "namespaces.h"
#include "path.h"
#include "map.h"
#include "symbol.h"
#include "srcline.h"
#include "dso.h"
+#include "dsos.h"
#include "machine.h"
#include "auxtrace.h"
#include "util.h" /* O_CLOEXEC for older systems */
@@ -766,7 +768,7 @@ dso_cache__free(struct dso *dso)
pthread_mutex_unlock(&dso->lock);
}
-static struct dso_cache *dso_cache__find(struct dso *dso, u64 offset)
+static struct dso_cache *__dso_cache__find(struct dso *dso, u64 offset)
{
const struct rb_root *root = &dso->data.cache;
struct rb_node * const *p = &root->rb_node;
@@ -825,14 +827,16 @@ out:
return cache;
}
-static ssize_t
-dso_cache__memcpy(struct dso_cache *cache, u64 offset,
- u8 *data, u64 size)
+static ssize_t dso_cache__memcpy(struct dso_cache *cache, u64 offset, u8 *data,
+ u64 size, bool out)
{
u64 cache_offset = offset - cache->offset;
u64 cache_size = min(cache->size - cache_offset, size);
- memcpy(data, cache->data + cache_offset, cache_size);
+ if (out)
+ memcpy(data, cache->data + cache_offset, cache_size);
+ else
+ memcpy(cache->data + cache_offset, data, cache_size);
return cache_size;
}
@@ -861,63 +865,73 @@ out:
return ret;
}
-static ssize_t
-dso_cache__read(struct dso *dso, struct machine *machine,
- u64 offset, u8 *data, ssize_t size)
+static struct dso_cache *dso_cache__populate(struct dso *dso,
+ struct machine *machine,
+ u64 offset, ssize_t *ret)
{
u64 cache_offset = offset & DSO__DATA_CACHE_MASK;
struct dso_cache *cache;
struct dso_cache *old;
- ssize_t ret;
cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
- if (!cache)
- return -ENOMEM;
+ if (!cache) {
+ *ret = -ENOMEM;
+ return NULL;
+ }
if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
- ret = bpf_read(dso, cache_offset, cache->data);
+ *ret = bpf_read(dso, cache_offset, cache->data);
else
- ret = file_read(dso, machine, cache_offset, cache->data);
+ *ret = file_read(dso, machine, cache_offset, cache->data);
- if (ret > 0) {
- cache->offset = cache_offset;
- cache->size = ret;
+ if (*ret <= 0) {
+ free(cache);
+ return NULL;
+ }
- old = dso_cache__insert(dso, cache);
- if (old) {
- /* we lose the race */
- free(cache);
- cache = old;
- }
+ cache->offset = cache_offset;
+ cache->size = *ret;
- ret = dso_cache__memcpy(cache, offset, data, size);
+ old = dso_cache__insert(dso, cache);
+ if (old) {
+ /* we lose the race */
+ free(cache);
+ cache = old;
}
- if (ret <= 0)
- free(cache);
+ return cache;
+}
- return ret;
+static struct dso_cache *dso_cache__find(struct dso *dso,
+ struct machine *machine,
+ u64 offset,
+ ssize_t *ret)
+{
+ struct dso_cache *cache = __dso_cache__find(dso, offset);
+
+ return cache ? cache : dso_cache__populate(dso, machine, offset, ret);
}
-static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
- u64 offset, u8 *data, ssize_t size)
+static ssize_t dso_cache_io(struct dso *dso, struct machine *machine,
+ u64 offset, u8 *data, ssize_t size, bool out)
{
struct dso_cache *cache;
+ ssize_t ret = 0;
- cache = dso_cache__find(dso, offset);
- if (cache)
- return dso_cache__memcpy(cache, offset, data, size);
- else
- return dso_cache__read(dso, machine, offset, data, size);
+ cache = dso_cache__find(dso, machine, offset, &ret);
+ if (!cache)
+ return ret;
+
+ return dso_cache__memcpy(cache, offset, data, size, out);
}
/*
* Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
* in the rb_tree. Any read to already cached data is served
- * by cached data.
+ * by cached data. Writes update the cache only, not the backing file.
*/
-static ssize_t cached_read(struct dso *dso, struct machine *machine,
- u64 offset, u8 *data, ssize_t size)
+static ssize_t cached_io(struct dso *dso, struct machine *machine,
+ u64 offset, u8 *data, ssize_t size, bool out)
{
ssize_t r = 0;
u8 *p = data;
@@ -925,7 +939,7 @@ static ssize_t cached_read(struct dso *dso, struct machine *machine,
do {
ssize_t ret;
- ret = dso_cache_read(dso, machine, offset, p, size);
+ ret = dso_cache_io(dso, machine, offset, p, size, out);
if (ret < 0)
return ret;
@@ -1009,8 +1023,9 @@ off_t dso__data_size(struct dso *dso, struct machine *machine)
return dso->data.file_size;
}
-static ssize_t data_read_offset(struct dso *dso, struct machine *machine,
- u64 offset, u8 *data, ssize_t size)
+static ssize_t data_read_write_offset(struct dso *dso, struct machine *machine,
+ u64 offset, u8 *data, ssize_t size,
+ bool out)
{
if (dso__data_file_size(dso, machine))
return -1;
@@ -1022,7 +1037,7 @@ static ssize_t data_read_offset(struct dso *dso, struct machine *machine,
if (offset + size < offset)
return -1;
- return cached_read(dso, machine, offset, data, size);
+ return cached_io(dso, machine, offset, data, size, out);
}
/**
@@ -1042,7 +1057,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
if (dso->data.status == DSO_DATA_STATUS_ERROR)
return -1;
- return data_read_offset(dso, machine, offset, data, size);
+ return data_read_write_offset(dso, machine, offset, data, size, true);
}
/**
@@ -1063,6 +1078,46 @@ ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
return dso__data_read_offset(dso, machine, offset, data, size);
}
+/**
+ * dso__data_write_cache_offs - Write data to dso data cache at file offset
+ * @dso: dso object
+ * @machine: machine object
+ * @offset: file offset
+ * @data: buffer to write
+ * @size: size of the @data buffer
+ *
+ * Write into the dso file data cache, but do not change the file itself.
+ */
+ssize_t dso__data_write_cache_offs(struct dso *dso, struct machine *machine,
+ u64 offset, const u8 *data_in, ssize_t size)
+{
+ u8 *data = (u8 *)data_in; /* cast away const to use same fns for r/w */
+
+ if (dso->data.status == DSO_DATA_STATUS_ERROR)
+ return -1;
+
+ return data_read_write_offset(dso, machine, offset, data, size, false);
+}
+
+/**
+ * dso__data_write_cache_addr - Write data to dso data cache at dso address
+ * @dso: dso object
+ * @machine: machine object
+ * @add: virtual memory address
+ * @data: buffer to write
+ * @size: size of the @data buffer
+ *
+ * External interface to write into the dso file data cache, but do not change
+ * the file itself.
+ */
+ssize_t dso__data_write_cache_addr(struct dso *dso, struct map *map,
+ struct machine *machine, u64 addr,
+ const u8 *data, ssize_t size)
+{
+ u64 offset = map->map_ip(map, addr);
+ return dso__data_write_cache_offs(dso, machine, offset, data, size);
+}
+
struct map *dso__new_map(const char *name)
{
struct map *map = NULL;
@@ -1094,67 +1149,7 @@ struct dso *machine__findnew_kernel(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 a 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);
- dso->root = root;
- }
- return NULL;
-}
-
-static inline struct dso *__dso__find_by_longname(struct rb_root *root,
- const char *name)
-{
- return __dso__findlink_by_longname(root, NULL, name);
-}
-
-void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
+static void dso__set_long_name_id(struct dso *dso, const char *name, struct dso_id *id, bool name_allocated)
{
struct rb_root *root = dso->root;
@@ -1167,8 +1162,8 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
if (root) {
rb_erase(&dso->rb_node, root);
/*
- * __dso__findlink_by_longname() isn't guaranteed to add it
- * back, so a clean removal is required here.
+ * __dsos__findnew_link_by_longname_id() isn't guaranteed to
+ * add it back, so a clean removal is required here.
*/
RB_CLEAR_NODE(&dso->rb_node);
dso->root = NULL;
@@ -1179,7 +1174,12 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
dso->long_name_allocated = name_allocated;
if (root)
- __dso__findlink_by_longname(root, dso, NULL);
+ __dsos__findnew_link_by_longname_id(root, dso, NULL, id);
+}
+
+void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
+{
+ dso__set_long_name_id(dso, name, NULL, name_allocated);
}
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
@@ -1195,38 +1195,6 @@ void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
dso->short_name_allocated = name_allocated;
}
-static void dso__set_basename(struct dso *dso)
-{
- char *base, *lname;
- int tid;
-
- if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) {
- if (asprintf(&base, "[JIT] tid %d", tid) < 0)
- return;
- } else {
- /*
- * basename() may modify path buffer, so we must pass
- * a copy.
- */
- lname = strdup(dso->long_name);
- if (!lname)
- return;
-
- /*
- * basename() may return a pointer to internal
- * storage which is reused in subsequent calls
- * so copy the result.
- */
- base = strdup(basename(lname));
-
- free(lname);
-
- if (!base)
- return;
- }
- dso__set_short_name(dso, base, true);
-}
-
int dso__name_len(const struct dso *dso)
{
if (!dso)
@@ -1252,13 +1220,15 @@ void dso__set_sorted_by_name(struct dso *dso)
dso->sorted_by_name = true;
}
-struct dso *dso__new(const char *name)
+struct dso *dso__new_id(const char *name, struct dso_id *id)
{
struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
if (dso != NULL) {
strcpy(dso->name, name);
- dso__set_long_name(dso, dso->name, false);
+ if (id)
+ dso->id = *id;
+ dso__set_long_name_id(dso, dso->name, id, false);
dso__set_short_name(dso, dso->name, false);
dso->symbols = dso->symbol_names = RB_ROOT_CACHED;
dso->data.cache = RB_ROOT;
@@ -1289,6 +1259,11 @@ struct dso *dso__new(const char *name)
return dso;
}
+struct dso *dso__new(const char *name)
+{
+ return dso__new_id(name, NULL);
+}
+
void dso__delete(struct dso *dso)
{
if (!RB_EMPTY_NODE(&dso->rb_node))
@@ -1377,143 +1352,6 @@ int dso__kernel_module_get_build_id(struct dso *dso,
return 0;
}
-bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
-{
- bool have_build_id = false;
- struct dso *pos;
- struct nscookie nsc;
-
- list_for_each_entry(pos, head, node) {
- if (with_hits && !pos->hit && !dso__is_vdso(pos))
- continue;
- if (pos->has_build_id) {
- have_build_id = true;
- continue;
- }
- nsinfo__mountns_enter(pos->nsinfo, &nsc);
- if (filename__read_build_id(pos->long_name, pos->build_id,
- sizeof(pos->build_id)) > 0) {
- have_build_id = true;
- pos->has_build_id = true;
- }
- nsinfo__mountns_exit(&nsc);
- }
-
- return have_build_id;
-}
-
-void __dsos__add(struct dsos *dsos, struct dso *dso)
-{
- list_add_tail(&dso->node, &dsos->head);
- __dso__findlink_by_longname(&dsos->root, dso, NULL);
- /*
- * It is now in the linked list, grab a reference, then garbage collect
- * this when needing memory, by looking at LRU dso instances in the
- * list with atomic_read(&dso->refcnt) == 1, i.e. no references
- * anywhere besides the one for the list, do, under a lock for the
- * list: remove it from the list, then a dso__put(), that probably will
- * be the last and will then call dso__delete(), end of life.
- *
- * That, or at the end of the 'struct machine' lifetime, when all
- * 'struct dso' instances will be removed from the list, in
- * dsos__exit(), if they have no other reference from some other data
- * structure.
- *
- * E.g.: after processing a 'perf.data' file and storing references
- * to objects instantiated while processing events, we will have
- * references to the 'thread', 'map', 'dso' structs all from 'struct
- * hist_entry' instances, but we may not need anything not referenced,
- * so we might as well call machines__exit()/machines__delete() and
- * garbage collect it.
- */
- dso__get(dso);
-}
-
-void dsos__add(struct dsos *dsos, struct dso *dso)
-{
- down_write(&dsos->lock);
- __dsos__add(dsos, dso);
- up_write(&dsos->lock);
-}
-
-struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
-{
- struct dso *pos;
-
- if (cmp_short) {
- list_for_each_entry(pos, &dsos->head, node)
- if (strcmp(pos->short_name, name) == 0)
- return pos;
- return NULL;
- }
- return __dso__find_by_longname(&dsos->root, name);
-}
-
-struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
-{
- struct dso *dso;
- down_read(&dsos->lock);
- dso = __dsos__find(dsos, name, cmp_short);
- up_read(&dsos->lock);
- return dso;
-}
-
-struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
-{
- struct dso *dso = dso__new(name);
-
- if (dso != NULL) {
- __dsos__add(dsos, dso);
- dso__set_basename(dso);
- /* Put dso here because __dsos_add already got it */
- dso__put(dso);
- }
- return dso;
-}
-
-struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
-{
- struct dso *dso = __dsos__find(dsos, name, false);
-
- return dso ? dso : __dsos__addnew(dsos, name);
-}
-
-struct dso *dsos__findnew(struct dsos *dsos, const char *name)
-{
- struct dso *dso;
- down_write(&dsos->lock);
- dso = dso__get(__dsos__findnew(dsos, name));
- up_write(&dsos->lock);
- return dso;
-}
-
-size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
- bool (skip)(struct dso *dso, int parm), int parm)
-{
- struct dso *pos;
- size_t ret = 0;
-
- list_for_each_entry(pos, head, node) {
- if (skip && skip(pos, parm))
- continue;
- ret += dso__fprintf_buildid(pos, fp);
- ret += fprintf(fp, " %s\n", pos->long_name);
- }
- return ret;
-}
-
-size_t __dsos__fprintf(struct list_head *head, FILE *fp)
-{
- struct dso *pos;
- size_t ret = 0;
-
- list_for_each_entry(pos, head, node) {
- ret += dso__fprintf(pos, fp);
- }
-
- return ret;
-}
-
size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
{
char sbuild_id[SBUILD_ID_SIZE];
OpenPOWER on IntegriCloud