diff options
Diffstat (limited to 'tools/perf/util/dso.c')
-rw-r--r-- | tools/perf/util/dso.c | 159 |
1 files changed, 112 insertions, 47 deletions
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index e11ddf86f2b3..91f21239608b 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -768,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; @@ -827,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; } @@ -863,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; @@ -927,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; @@ -1011,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; @@ -1024,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); } /** @@ -1044,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); } /** @@ -1065,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; @@ -1096,7 +1149,7 @@ struct dso *machine__findnew_kernel(struct machine *machine, const char *name, return dso; } -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; @@ -1109,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); /* - * __dsos__findnew_link_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; @@ -1121,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) - __dsos__findnew_link_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) @@ -1162,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; @@ -1199,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)) |