summaryrefslogtreecommitdiff
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.c121
1 files changed, 93 insertions, 28 deletions
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 90d02c66..0247acf 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
{
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
int ret = 0;
+ size_t len;
switch (type) {
case DSO_BINARY_TYPE__DEBUGLINK: {
@@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso,
break;
case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
- snprintf(filename, size, "%s/usr/lib/debug%s.debug",
- symbol_conf.symfs, dso->long_name);
+ len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+ snprintf(filename + len, size - len, "%s.debug", dso->long_name);
break;
case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
- snprintf(filename, size, "%s/usr/lib/debug%s",
- symbol_conf.symfs, dso->long_name);
+ len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+ snprintf(filename + len, size - len, "%s", dso->long_name);
break;
case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
{
const char *last_slash;
- size_t len;
size_t dir_size;
last_slash = dso->long_name + dso->long_name_len;
while (last_slash != dso->long_name && *last_slash != '/')
last_slash--;
- len = scnprintf(filename, size, "%s", symbol_conf.symfs);
+ len = __symbol__join_symfs(filename, size, "");
dir_size = last_slash - dso->long_name + 2;
if (dir_size > (size - len)) {
ret = -1;
@@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso,
build_id__sprintf(dso->build_id,
sizeof(dso->build_id),
build_id_hex);
- snprintf(filename, size,
- "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
- symbol_conf.symfs, build_id_hex, build_id_hex + 2);
+ len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
+ snprintf(filename + len, size - len, "%.2s/%s.debug",
+ build_id_hex, build_id_hex + 2);
break;
case DSO_BINARY_TYPE__VMLINUX:
case DSO_BINARY_TYPE__GUEST_VMLINUX:
case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
- snprintf(filename, size, "%s%s",
- symbol_conf.symfs, dso->long_name);
+ __symbol__join_symfs(filename, size, dso->long_name);
break;
case DSO_BINARY_TYPE__GUEST_KMODULE:
- snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
- root_dir, dso->long_name);
+ path__join3(filename, size, symbol_conf.symfs,
+ root_dir, dso->long_name);
break;
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
- snprintf(filename, size, "%s%s", symbol_conf.symfs,
- dso->long_name);
+ __symbol__join_symfs(filename, size, dso->long_name);
break;
case DSO_BINARY_TYPE__KCORE:
@@ -164,13 +162,15 @@ static void close_first_dso(void);
static int do_open(char *name)
{
int fd;
+ char sbuf[STRERR_BUFSIZE];
do {
fd = open(name, O_RDONLY);
if (fd >= 0)
return fd;
- pr_debug("dso open failed, mmap: %s\n", strerror(errno));
+ pr_debug("dso open failed, mmap: %s\n",
+ strerror_r(errno, sbuf, sizeof(sbuf)));
if (!dso__data_open_cnt || errno != EMFILE)
break;
@@ -532,10 +532,12 @@ static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
static int data_file_size(struct dso *dso)
{
struct stat st;
+ char sbuf[STRERR_BUFSIZE];
if (!dso->data.file_size) {
if (fstat(dso->data.fd, &st)) {
- pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
+ pr_err("dso mmap failed, fstat: %s\n",
+ strerror_r(errno, sbuf, sizeof(sbuf)));
return -1;
}
dso->data.file_size = st.st_size;
@@ -651,6 +653,65 @@ struct dso *dso__kernel_findnew(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 an 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);
+ }
+ return NULL;
+}
+
+static inline struct dso *
+dso__find_by_longname(const struct rb_root *root, const char *name)
+{
+ return dso__findlink_by_longname((struct rb_root *)root, NULL, name);
+}
+
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
{
if (name == NULL)
@@ -753,6 +814,7 @@ struct dso *dso__new(const char *name)
dso->a2l_fails = 1;
dso->kernel = DSO_TYPE_USER;
dso->needs_swap = DSO_SWAP__UNSET;
+ RB_CLEAR_NODE(&dso->rb_node);
INIT_LIST_HEAD(&dso->node);
INIT_LIST_HEAD(&dso->data.open_entry);
}
@@ -763,6 +825,10 @@ struct dso *dso__new(const char *name)
void dso__delete(struct dso *dso)
{
int i;
+
+ if (!RB_EMPTY_NODE(&dso->rb_node))
+ pr_err("DSO %s is still in rbtree when being deleted!\n",
+ dso->long_name);
for (i = 0; i < MAP__NR_TYPES; ++i)
symbols__delete(&dso->symbols[i]);
@@ -849,35 +915,34 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
return have_build_id;
}
-void dsos__add(struct list_head *head, struct dso *dso)
+void dsos__add(struct dsos *dsos, struct dso *dso)
{
- list_add_tail(&dso->node, head);
+ list_add_tail(&dso->node, &dsos->head);
+ dso__findlink_by_longname(&dsos->root, dso, NULL);
}
-struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short)
+struct dso *dsos__find(const struct dsos *dsos, const char *name,
+ bool cmp_short)
{
struct dso *pos;
if (cmp_short) {
- list_for_each_entry(pos, head, node)
+ list_for_each_entry(pos, &dsos->head, node)
if (strcmp(pos->short_name, name) == 0)
return pos;
return NULL;
}
- list_for_each_entry(pos, head, node)
- if (strcmp(pos->long_name, name) == 0)
- return pos;
- return NULL;
+ return dso__find_by_longname(&dsos->root, name);
}
-struct dso *__dsos__findnew(struct list_head *head, const char *name)
+struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
{
- struct dso *dso = dsos__find(head, name, false);
+ struct dso *dso = dsos__find(dsos, name, false);
if (!dso) {
dso = dso__new(name);
if (dso != NULL) {
- dsos__add(head, dso);
+ dsos__add(dsos, dso);
dso__set_basename(dso);
}
}