Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include "debug.h"
0003 #include "dsos.h"
0004 #include "dso.h"
0005 #include "util.h"
0006 #include "vdso.h"
0007 #include "namespaces.h"
0008 #include <errno.h>
0009 #include <libgen.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012 #include <symbol.h> // filename__read_build_id
0013 #include <unistd.h>
0014 
0015 static int __dso_id__cmp(struct dso_id *a, struct dso_id *b)
0016 {
0017     if (a->maj > b->maj) return -1;
0018     if (a->maj < b->maj) return 1;
0019 
0020     if (a->min > b->min) return -1;
0021     if (a->min < b->min) return 1;
0022 
0023     if (a->ino > b->ino) return -1;
0024     if (a->ino < b->ino) return 1;
0025 
0026     /*
0027      * Synthesized MMAP events have zero ino_generation, avoid comparing
0028      * them with MMAP events with actual ino_generation.
0029      *
0030      * I found it harmful because the mismatch resulted in a new
0031      * dso that did not have a build ID whereas the original dso did have a
0032      * build ID. The build ID was essential because the object was not found
0033      * otherwise. - Adrian
0034      */
0035     if (a->ino_generation && b->ino_generation) {
0036         if (a->ino_generation > b->ino_generation) return -1;
0037         if (a->ino_generation < b->ino_generation) return 1;
0038     }
0039 
0040     return 0;
0041 }
0042 
0043 static bool dso_id__empty(struct dso_id *id)
0044 {
0045     if (!id)
0046         return true;
0047 
0048     return !id->maj && !id->min && !id->ino && !id->ino_generation;
0049 }
0050 
0051 static void dso__inject_id(struct dso *dso, struct dso_id *id)
0052 {
0053     dso->id.maj = id->maj;
0054     dso->id.min = id->min;
0055     dso->id.ino = id->ino;
0056     dso->id.ino_generation = id->ino_generation;
0057 }
0058 
0059 static int dso_id__cmp(struct dso_id *a, struct dso_id *b)
0060 {
0061     /*
0062      * The second is always dso->id, so zeroes if not set, assume passing
0063      * NULL for a means a zeroed id
0064      */
0065     if (dso_id__empty(a) || dso_id__empty(b))
0066         return 0;
0067 
0068     return __dso_id__cmp(a, b);
0069 }
0070 
0071 int dso__cmp_id(struct dso *a, struct dso *b)
0072 {
0073     return __dso_id__cmp(&a->id, &b->id);
0074 }
0075 
0076 bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
0077 {
0078     bool have_build_id = false;
0079     struct dso *pos;
0080     struct nscookie nsc;
0081 
0082     list_for_each_entry(pos, head, node) {
0083         if (with_hits && !pos->hit && !dso__is_vdso(pos))
0084             continue;
0085         if (pos->has_build_id) {
0086             have_build_id = true;
0087             continue;
0088         }
0089         nsinfo__mountns_enter(pos->nsinfo, &nsc);
0090         if (filename__read_build_id(pos->long_name, &pos->bid) > 0) {
0091             have_build_id     = true;
0092             pos->has_build_id = true;
0093         } else if (errno == ENOENT && pos->nsinfo) {
0094             char *new_name = filename_with_chroot(pos->nsinfo->pid,
0095                                   pos->long_name);
0096 
0097             if (new_name && filename__read_build_id(new_name,
0098                                 &pos->bid) > 0) {
0099                 have_build_id = true;
0100                 pos->has_build_id = true;
0101             }
0102             free(new_name);
0103         }
0104         nsinfo__mountns_exit(&nsc);
0105     }
0106 
0107     return have_build_id;
0108 }
0109 
0110 static int __dso__cmp_long_name(const char *long_name, struct dso_id *id, struct dso *b)
0111 {
0112     int rc = strcmp(long_name, b->long_name);
0113     return rc ?: dso_id__cmp(id, &b->id);
0114 }
0115 
0116 static int __dso__cmp_short_name(const char *short_name, struct dso_id *id, struct dso *b)
0117 {
0118     int rc = strcmp(short_name, b->short_name);
0119     return rc ?: dso_id__cmp(id, &b->id);
0120 }
0121 
0122 static int dso__cmp_short_name(struct dso *a, struct dso *b)
0123 {
0124     return __dso__cmp_short_name(a->short_name, &a->id, b);
0125 }
0126 
0127 /*
0128  * Find a matching entry and/or link current entry to RB tree.
0129  * Either one of the dso or name parameter must be non-NULL or the
0130  * function will not work.
0131  */
0132 struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso *dso,
0133                         const char *name, struct dso_id *id)
0134 {
0135     struct rb_node **p = &root->rb_node;
0136     struct rb_node  *parent = NULL;
0137 
0138     if (!name)
0139         name = dso->long_name;
0140     /*
0141      * Find node with the matching name
0142      */
0143     while (*p) {
0144         struct dso *this = rb_entry(*p, struct dso, rb_node);
0145         int rc = __dso__cmp_long_name(name, id, this);
0146 
0147         parent = *p;
0148         if (rc == 0) {
0149             /*
0150              * In case the new DSO is a duplicate of an existing
0151              * one, print a one-time warning & put the new entry
0152              * at the end of the list of duplicates.
0153              */
0154             if (!dso || (dso == this))
0155                 return this;    /* Find matching dso */
0156             /*
0157              * The core kernel DSOs may have duplicated long name.
0158              * In this case, the short name should be different.
0159              * Comparing the short names to differentiate the DSOs.
0160              */
0161             rc = dso__cmp_short_name(dso, this);
0162             if (rc == 0) {
0163                 pr_err("Duplicated dso name: %s\n", name);
0164                 return NULL;
0165             }
0166         }
0167         if (rc < 0)
0168             p = &parent->rb_left;
0169         else
0170             p = &parent->rb_right;
0171     }
0172     if (dso) {
0173         /* Add new node and rebalance tree */
0174         rb_link_node(&dso->rb_node, parent, p);
0175         rb_insert_color(&dso->rb_node, root);
0176         dso->root = root;
0177     }
0178     return NULL;
0179 }
0180 
0181 void __dsos__add(struct dsos *dsos, struct dso *dso)
0182 {
0183     list_add_tail(&dso->node, &dsos->head);
0184     __dsos__findnew_link_by_longname_id(&dsos->root, dso, NULL, &dso->id);
0185     /*
0186      * It is now in the linked list, grab a reference, then garbage collect
0187      * this when needing memory, by looking at LRU dso instances in the
0188      * list with atomic_read(&dso->refcnt) == 1, i.e. no references
0189      * anywhere besides the one for the list, do, under a lock for the
0190      * list: remove it from the list, then a dso__put(), that probably will
0191      * be the last and will then call dso__delete(), end of life.
0192      *
0193      * That, or at the end of the 'struct machine' lifetime, when all
0194      * 'struct dso' instances will be removed from the list, in
0195      * dsos__exit(), if they have no other reference from some other data
0196      * structure.
0197      *
0198      * E.g.: after processing a 'perf.data' file and storing references
0199      * to objects instantiated while processing events, we will have
0200      * references to the 'thread', 'map', 'dso' structs all from 'struct
0201      * hist_entry' instances, but we may not need anything not referenced,
0202      * so we might as well call machines__exit()/machines__delete() and
0203      * garbage collect it.
0204      */
0205     dso__get(dso);
0206 }
0207 
0208 void dsos__add(struct dsos *dsos, struct dso *dso)
0209 {
0210     down_write(&dsos->lock);
0211     __dsos__add(dsos, dso);
0212     up_write(&dsos->lock);
0213 }
0214 
0215 static struct dso *__dsos__findnew_by_longname_id(struct rb_root *root, const char *name, struct dso_id *id)
0216 {
0217     return __dsos__findnew_link_by_longname_id(root, NULL, name, id);
0218 }
0219 
0220 static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, struct dso_id *id, bool cmp_short)
0221 {
0222     struct dso *pos;
0223 
0224     if (cmp_short) {
0225         list_for_each_entry(pos, &dsos->head, node)
0226             if (__dso__cmp_short_name(name, id, pos) == 0)
0227                 return pos;
0228         return NULL;
0229     }
0230     return __dsos__findnew_by_longname_id(&dsos->root, name, id);
0231 }
0232 
0233 struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
0234 {
0235     return __dsos__find_id(dsos, name, NULL, cmp_short);
0236 }
0237 
0238 static void dso__set_basename(struct dso *dso)
0239 {
0240     char *base, *lname;
0241     int tid;
0242 
0243     if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) {
0244         if (asprintf(&base, "[JIT] tid %d", tid) < 0)
0245             return;
0246     } else {
0247           /*
0248            * basename() may modify path buffer, so we must pass
0249                * a copy.
0250                */
0251         lname = strdup(dso->long_name);
0252         if (!lname)
0253             return;
0254 
0255         /*
0256          * basename() may return a pointer to internal
0257          * storage which is reused in subsequent calls
0258          * so copy the result.
0259          */
0260         base = strdup(basename(lname));
0261 
0262         free(lname);
0263 
0264         if (!base)
0265             return;
0266     }
0267     dso__set_short_name(dso, base, true);
0268 }
0269 
0270 static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
0271 {
0272     struct dso *dso = dso__new_id(name, id);
0273 
0274     if (dso != NULL) {
0275         __dsos__add(dsos, dso);
0276         dso__set_basename(dso);
0277         /* Put dso here because __dsos_add already got it */
0278         dso__put(dso);
0279     }
0280     return dso;
0281 }
0282 
0283 struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
0284 {
0285     return __dsos__addnew_id(dsos, name, NULL);
0286 }
0287 
0288 static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
0289 {
0290     struct dso *dso = __dsos__find_id(dsos, name, id, false);
0291 
0292     if (dso && dso_id__empty(&dso->id) && !dso_id__empty(id))
0293         dso__inject_id(dso, id);
0294 
0295     return dso ? dso : __dsos__addnew_id(dsos, name, id);
0296 }
0297 
0298 struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
0299 {
0300     struct dso *dso;
0301     down_write(&dsos->lock);
0302     dso = dso__get(__dsos__findnew_id(dsos, name, id));
0303     up_write(&dsos->lock);
0304     return dso;
0305 }
0306 
0307 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
0308                    bool (skip)(struct dso *dso, int parm), int parm)
0309 {
0310     struct dso *pos;
0311     size_t ret = 0;
0312 
0313     list_for_each_entry(pos, head, node) {
0314         char sbuild_id[SBUILD_ID_SIZE];
0315 
0316         if (skip && skip(pos, parm))
0317             continue;
0318         build_id__sprintf(&pos->bid, sbuild_id);
0319         ret += fprintf(fp, "%-40s %s\n", sbuild_id, pos->long_name);
0320     }
0321     return ret;
0322 }
0323 
0324 size_t __dsos__fprintf(struct list_head *head, FILE *fp)
0325 {
0326     struct dso *pos;
0327     size_t ret = 0;
0328 
0329     list_for_each_entry(pos, head, node) {
0330         ret += dso__fprintf(pos, fp);
0331     }
0332 
0333     return ret;
0334 }