root/tools/perf/util/dsos.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __dsos__read_build_ids
  2. __dsos__findnew_link_by_longname
  3. __dsos__add
  4. dsos__add
  5. __dsos__find
  6. dsos__find
  7. dso__set_basename
  8. __dsos__addnew
  9. __dsos__findnew
  10. dsos__findnew
  11. __dsos__fprintf_buildid
  12. __dsos__fprintf

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include "debug.h"
   3 #include "dsos.h"
   4 #include "dso.h"
   5 #include "vdso.h"
   6 #include "namespaces.h"
   7 #include <libgen.h>
   8 #include <stdlib.h>
   9 #include <string.h>
  10 #include <symbol.h> // filename__read_build_id
  11 
  12 bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
  13 {
  14         bool have_build_id = false;
  15         struct dso *pos;
  16         struct nscookie nsc;
  17 
  18         list_for_each_entry(pos, head, node) {
  19                 if (with_hits && !pos->hit && !dso__is_vdso(pos))
  20                         continue;
  21                 if (pos->has_build_id) {
  22                         have_build_id = true;
  23                         continue;
  24                 }
  25                 nsinfo__mountns_enter(pos->nsinfo, &nsc);
  26                 if (filename__read_build_id(pos->long_name, pos->build_id,
  27                                             sizeof(pos->build_id)) > 0) {
  28                         have_build_id     = true;
  29                         pos->has_build_id = true;
  30                 }
  31                 nsinfo__mountns_exit(&nsc);
  32         }
  33 
  34         return have_build_id;
  35 }
  36 
  37 /*
  38  * Find a matching entry and/or link current entry to RB tree.
  39  * Either one of the dso or name parameter must be non-NULL or the
  40  * function will not work.
  41  */
  42 struct dso *__dsos__findnew_link_by_longname(struct rb_root *root, struct dso *dso, const char *name)
  43 {
  44         struct rb_node **p = &root->rb_node;
  45         struct rb_node  *parent = NULL;
  46 
  47         if (!name)
  48                 name = dso->long_name;
  49         /*
  50          * Find node with the matching name
  51          */
  52         while (*p) {
  53                 struct dso *this = rb_entry(*p, struct dso, rb_node);
  54                 int rc = strcmp(name, this->long_name);
  55 
  56                 parent = *p;
  57                 if (rc == 0) {
  58                         /*
  59                          * In case the new DSO is a duplicate of an existing
  60                          * one, print a one-time warning & put the new entry
  61                          * at the end of the list of duplicates.
  62                          */
  63                         if (!dso || (dso == this))
  64                                 return this;    /* Find matching dso */
  65                         /*
  66                          * The core kernel DSOs may have duplicated long name.
  67                          * In this case, the short name should be different.
  68                          * Comparing the short names to differentiate the DSOs.
  69                          */
  70                         rc = strcmp(dso->short_name, this->short_name);
  71                         if (rc == 0) {
  72                                 pr_err("Duplicated dso name: %s\n", name);
  73                                 return NULL;
  74                         }
  75                 }
  76                 if (rc < 0)
  77                         p = &parent->rb_left;
  78                 else
  79                         p = &parent->rb_right;
  80         }
  81         if (dso) {
  82                 /* Add new node and rebalance tree */
  83                 rb_link_node(&dso->rb_node, parent, p);
  84                 rb_insert_color(&dso->rb_node, root);
  85                 dso->root = root;
  86         }
  87         return NULL;
  88 }
  89 
  90 void __dsos__add(struct dsos *dsos, struct dso *dso)
  91 {
  92         list_add_tail(&dso->node, &dsos->head);
  93         __dsos__findnew_link_by_longname(&dsos->root, dso, NULL);
  94         /*
  95          * It is now in the linked list, grab a reference, then garbage collect
  96          * this when needing memory, by looking at LRU dso instances in the
  97          * list with atomic_read(&dso->refcnt) == 1, i.e. no references
  98          * anywhere besides the one for the list, do, under a lock for the
  99          * list: remove it from the list, then a dso__put(), that probably will
 100          * be the last and will then call dso__delete(), end of life.
 101          *
 102          * That, or at the end of the 'struct machine' lifetime, when all
 103          * 'struct dso' instances will be removed from the list, in
 104          * dsos__exit(), if they have no other reference from some other data
 105          * structure.
 106          *
 107          * E.g.: after processing a 'perf.data' file and storing references
 108          * to objects instantiated while processing events, we will have
 109          * references to the 'thread', 'map', 'dso' structs all from 'struct
 110          * hist_entry' instances, but we may not need anything not referenced,
 111          * so we might as well call machines__exit()/machines__delete() and
 112          * garbage collect it.
 113          */
 114         dso__get(dso);
 115 }
 116 
 117 void dsos__add(struct dsos *dsos, struct dso *dso)
 118 {
 119         down_write(&dsos->lock);
 120         __dsos__add(dsos, dso);
 121         up_write(&dsos->lock);
 122 }
 123 
 124 struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
 125 {
 126         struct dso *pos;
 127 
 128         if (cmp_short) {
 129                 list_for_each_entry(pos, &dsos->head, node)
 130                         if (strcmp(pos->short_name, name) == 0)
 131                                 return pos;
 132                 return NULL;
 133         }
 134         return __dsos__findnew_by_longname(&dsos->root, name);
 135 }
 136 
 137 struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
 138 {
 139         struct dso *dso;
 140         down_read(&dsos->lock);
 141         dso = __dsos__find(dsos, name, cmp_short);
 142         up_read(&dsos->lock);
 143         return dso;
 144 }
 145 
 146 static void dso__set_basename(struct dso *dso)
 147 {
 148         char *base, *lname;
 149         int tid;
 150 
 151         if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) {
 152                 if (asprintf(&base, "[JIT] tid %d", tid) < 0)
 153                         return;
 154         } else {
 155               /*
 156                * basename() may modify path buffer, so we must pass
 157                * a copy.
 158                */
 159                 lname = strdup(dso->long_name);
 160                 if (!lname)
 161                         return;
 162 
 163                 /*
 164                  * basename() may return a pointer to internal
 165                  * storage which is reused in subsequent calls
 166                  * so copy the result.
 167                  */
 168                 base = strdup(basename(lname));
 169 
 170                 free(lname);
 171 
 172                 if (!base)
 173                         return;
 174         }
 175         dso__set_short_name(dso, base, true);
 176 }
 177 
 178 struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
 179 {
 180         struct dso *dso = dso__new(name);
 181 
 182         if (dso != NULL) {
 183                 __dsos__add(dsos, dso);
 184                 dso__set_basename(dso);
 185                 /* Put dso here because __dsos_add already got it */
 186                 dso__put(dso);
 187         }
 188         return dso;
 189 }
 190 
 191 struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
 192 {
 193         struct dso *dso = __dsos__find(dsos, name, false);
 194 
 195         return dso ? dso : __dsos__addnew(dsos, name);
 196 }
 197 
 198 struct dso *dsos__findnew(struct dsos *dsos, const char *name)
 199 {
 200         struct dso *dso;
 201         down_write(&dsos->lock);
 202         dso = dso__get(__dsos__findnew(dsos, name));
 203         up_write(&dsos->lock);
 204         return dso;
 205 }
 206 
 207 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
 208                                bool (skip)(struct dso *dso, int parm), int parm)
 209 {
 210         struct dso *pos;
 211         size_t ret = 0;
 212 
 213         list_for_each_entry(pos, head, node) {
 214                 if (skip && skip(pos, parm))
 215                         continue;
 216                 ret += dso__fprintf_buildid(pos, fp);
 217                 ret += fprintf(fp, " %s\n", pos->long_name);
 218         }
 219         return ret;
 220 }
 221 
 222 size_t __dsos__fprintf(struct list_head *head, FILE *fp)
 223 {
 224         struct dso *pos;
 225         size_t ret = 0;
 226 
 227         list_for_each_entry(pos, head, node) {
 228                 ret += dso__fprintf(pos, fp);
 229         }
 230 
 231         return ret;
 232 }

/* [<][>][^][v][top][bottom][index][help] */