GNU Linux-libre 5.10.217-gnu1
[releases.git] / tools / perf / util / dsos.c
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 static int __dso_id__cmp(struct dso_id *a, struct dso_id *b)
13 {
14         if (a->maj > b->maj) return -1;
15         if (a->maj < b->maj) return 1;
16
17         if (a->min > b->min) return -1;
18         if (a->min < b->min) return 1;
19
20         if (a->ino > b->ino) return -1;
21         if (a->ino < b->ino) return 1;
22
23         /*
24          * Synthesized MMAP events have zero ino_generation, avoid comparing
25          * them with MMAP events with actual ino_generation.
26          *
27          * I found it harmful because the mismatch resulted in a new
28          * dso that did not have a build ID whereas the original dso did have a
29          * build ID. The build ID was essential because the object was not found
30          * otherwise. - Adrian
31          */
32         if (a->ino_generation && b->ino_generation) {
33                 if (a->ino_generation > b->ino_generation) return -1;
34                 if (a->ino_generation < b->ino_generation) return 1;
35         }
36
37         return 0;
38 }
39
40 static bool dso_id__empty(struct dso_id *id)
41 {
42         if (!id)
43                 return true;
44
45         return !id->maj && !id->min && !id->ino && !id->ino_generation;
46 }
47
48 static void dso__inject_id(struct dso *dso, struct dso_id *id)
49 {
50         dso->id.maj = id->maj;
51         dso->id.min = id->min;
52         dso->id.ino = id->ino;
53         dso->id.ino_generation = id->ino_generation;
54 }
55
56 static int dso_id__cmp(struct dso_id *a, struct dso_id *b)
57 {
58         /*
59          * The second is always dso->id, so zeroes if not set, assume passing
60          * NULL for a means a zeroed id
61          */
62         if (dso_id__empty(a) || dso_id__empty(b))
63                 return 0;
64
65         return __dso_id__cmp(a, b);
66 }
67
68 int dso__cmp_id(struct dso *a, struct dso *b)
69 {
70         return __dso_id__cmp(&a->id, &b->id);
71 }
72
73 bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
74 {
75         bool have_build_id = false;
76         struct dso *pos;
77         struct nscookie nsc;
78
79         list_for_each_entry(pos, head, node) {
80                 if (with_hits && !pos->hit && !dso__is_vdso(pos))
81                         continue;
82                 if (pos->has_build_id) {
83                         have_build_id = true;
84                         continue;
85                 }
86                 nsinfo__mountns_enter(pos->nsinfo, &nsc);
87                 if (filename__read_build_id(pos->long_name, &pos->bid) > 0) {
88                         have_build_id     = true;
89                         pos->has_build_id = true;
90                 }
91                 nsinfo__mountns_exit(&nsc);
92         }
93
94         return have_build_id;
95 }
96
97 static int __dso__cmp_long_name(const char *long_name, struct dso_id *id, struct dso *b)
98 {
99         int rc = strcmp(long_name, b->long_name);
100         return rc ?: dso_id__cmp(id, &b->id);
101 }
102
103 static int __dso__cmp_short_name(const char *short_name, struct dso_id *id, struct dso *b)
104 {
105         int rc = strcmp(short_name, b->short_name);
106         return rc ?: dso_id__cmp(id, &b->id);
107 }
108
109 static int dso__cmp_short_name(struct dso *a, struct dso *b)
110 {
111         return __dso__cmp_short_name(a->short_name, &a->id, b);
112 }
113
114 /*
115  * Find a matching entry and/or link current entry to RB tree.
116  * Either one of the dso or name parameter must be non-NULL or the
117  * function will not work.
118  */
119 struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso *dso,
120                                                 const char *name, struct dso_id *id)
121 {
122         struct rb_node **p = &root->rb_node;
123         struct rb_node  *parent = NULL;
124
125         if (!name)
126                 name = dso->long_name;
127         /*
128          * Find node with the matching name
129          */
130         while (*p) {
131                 struct dso *this = rb_entry(*p, struct dso, rb_node);
132                 int rc = __dso__cmp_long_name(name, id, this);
133
134                 parent = *p;
135                 if (rc == 0) {
136                         /*
137                          * In case the new DSO is a duplicate of an existing
138                          * one, print a one-time warning & put the new entry
139                          * at the end of the list of duplicates.
140                          */
141                         if (!dso || (dso == this))
142                                 return this;    /* Find matching dso */
143                         /*
144                          * The core kernel DSOs may have duplicated long name.
145                          * In this case, the short name should be different.
146                          * Comparing the short names to differentiate the DSOs.
147                          */
148                         rc = dso__cmp_short_name(dso, this);
149                         if (rc == 0) {
150                                 pr_err("Duplicated dso name: %s\n", name);
151                                 return NULL;
152                         }
153                 }
154                 if (rc < 0)
155                         p = &parent->rb_left;
156                 else
157                         p = &parent->rb_right;
158         }
159         if (dso) {
160                 /* Add new node and rebalance tree */
161                 rb_link_node(&dso->rb_node, parent, p);
162                 rb_insert_color(&dso->rb_node, root);
163                 dso->root = root;
164         }
165         return NULL;
166 }
167
168 void __dsos__add(struct dsos *dsos, struct dso *dso)
169 {
170         list_add_tail(&dso->node, &dsos->head);
171         __dsos__findnew_link_by_longname_id(&dsos->root, dso, NULL, &dso->id);
172         /*
173          * It is now in the linked list, grab a reference, then garbage collect
174          * this when needing memory, by looking at LRU dso instances in the
175          * list with atomic_read(&dso->refcnt) == 1, i.e. no references
176          * anywhere besides the one for the list, do, under a lock for the
177          * list: remove it from the list, then a dso__put(), that probably will
178          * be the last and will then call dso__delete(), end of life.
179          *
180          * That, or at the end of the 'struct machine' lifetime, when all
181          * 'struct dso' instances will be removed from the list, in
182          * dsos__exit(), if they have no other reference from some other data
183          * structure.
184          *
185          * E.g.: after processing a 'perf.data' file and storing references
186          * to objects instantiated while processing events, we will have
187          * references to the 'thread', 'map', 'dso' structs all from 'struct
188          * hist_entry' instances, but we may not need anything not referenced,
189          * so we might as well call machines__exit()/machines__delete() and
190          * garbage collect it.
191          */
192         dso__get(dso);
193 }
194
195 void dsos__add(struct dsos *dsos, struct dso *dso)
196 {
197         down_write(&dsos->lock);
198         __dsos__add(dsos, dso);
199         up_write(&dsos->lock);
200 }
201
202 static struct dso *__dsos__findnew_by_longname_id(struct rb_root *root, const char *name, struct dso_id *id)
203 {
204         return __dsos__findnew_link_by_longname_id(root, NULL, name, id);
205 }
206
207 static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, struct dso_id *id, bool cmp_short)
208 {
209         struct dso *pos;
210
211         if (cmp_short) {
212                 list_for_each_entry(pos, &dsos->head, node)
213                         if (__dso__cmp_short_name(name, id, pos) == 0)
214                                 return pos;
215                 return NULL;
216         }
217         return __dsos__findnew_by_longname_id(&dsos->root, name, id);
218 }
219
220 struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
221 {
222         return __dsos__find_id(dsos, name, NULL, cmp_short);
223 }
224
225 static void dso__set_basename(struct dso *dso)
226 {
227         char *base, *lname;
228         int tid;
229
230         if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) {
231                 if (asprintf(&base, "[JIT] tid %d", tid) < 0)
232                         return;
233         } else {
234               /*
235                * basename() may modify path buffer, so we must pass
236                * a copy.
237                */
238                 lname = strdup(dso->long_name);
239                 if (!lname)
240                         return;
241
242                 /*
243                  * basename() may return a pointer to internal
244                  * storage which is reused in subsequent calls
245                  * so copy the result.
246                  */
247                 base = strdup(basename(lname));
248
249                 free(lname);
250
251                 if (!base)
252                         return;
253         }
254         dso__set_short_name(dso, base, true);
255 }
256
257 static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
258 {
259         struct dso *dso = dso__new_id(name, id);
260
261         if (dso != NULL) {
262                 __dsos__add(dsos, dso);
263                 dso__set_basename(dso);
264                 /* Put dso here because __dsos_add already got it */
265                 dso__put(dso);
266         }
267         return dso;
268 }
269
270 struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
271 {
272         return __dsos__addnew_id(dsos, name, NULL);
273 }
274
275 static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
276 {
277         struct dso *dso = __dsos__find_id(dsos, name, id, false);
278
279         if (dso && dso_id__empty(&dso->id) && !dso_id__empty(id))
280                 dso__inject_id(dso, id);
281
282         return dso ? dso : __dsos__addnew_id(dsos, name, id);
283 }
284
285 struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
286 {
287         struct dso *dso;
288         down_write(&dsos->lock);
289         dso = dso__get(__dsos__findnew_id(dsos, name, id));
290         up_write(&dsos->lock);
291         return dso;
292 }
293
294 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
295                                bool (skip)(struct dso *dso, int parm), int parm)
296 {
297         struct dso *pos;
298         size_t ret = 0;
299
300         list_for_each_entry(pos, head, node) {
301                 char sbuild_id[SBUILD_ID_SIZE];
302
303                 if (skip && skip(pos, parm))
304                         continue;
305                 build_id__sprintf(&pos->bid, sbuild_id);
306                 ret += fprintf(fp, "%-40s %s\n", sbuild_id, pos->long_name);
307         }
308         return ret;
309 }
310
311 size_t __dsos__fprintf(struct list_head *head, FILE *fp)
312 {
313         struct dso *pos;
314         size_t ret = 0;
315
316         list_for_each_entry(pos, head, node) {
317                 ret += dso__fprintf(pos, fp);
318         }
319
320         return ret;
321 }