1 // SPDX-License-Identifier: GPL-2.0
7 #include "namespaces.h"
12 #include <symbol.h> // filename__read_build_id
15 void dsos__init(struct dsos
*dsos
)
17 init_rwsem(&dsos
->lock
);
25 static void dsos__purge(struct dsos
*dsos
)
27 down_write(&dsos
->lock
);
29 for (unsigned int i
= 0; i
< dsos
->cnt
; i
++) {
30 struct dso
*dso
= dsos
->dsos
[i
];
32 dso__set_dsos(dso
, NULL
);
41 up_write(&dsos
->lock
);
44 void dsos__exit(struct dsos
*dsos
)
47 exit_rwsem(&dsos
->lock
);
51 static int __dsos__for_each_dso(struct dsos
*dsos
,
52 int (*cb
)(struct dso
*dso
, void *data
),
55 for (unsigned int i
= 0; i
< dsos
->cnt
; i
++) {
56 struct dso
*dso
= dsos
->dsos
[i
];
66 struct dsos__read_build_ids_cb_args
{
71 static int dsos__read_build_ids_cb(struct dso
*dso
, void *data
)
73 struct dsos__read_build_ids_cb_args
*args
= data
;
76 if (args
->with_hits
&& !dso__hit(dso
) && !dso__is_vdso(dso
))
78 if (dso__has_build_id(dso
)) {
79 args
->have_build_id
= true;
82 nsinfo__mountns_enter(dso__nsinfo(dso
), &nsc
);
83 if (filename__read_build_id(dso__long_name(dso
), dso__bid(dso
)) > 0) {
84 args
->have_build_id
= true;
85 dso__set_has_build_id(dso
);
86 } else if (errno
== ENOENT
&& dso__nsinfo(dso
)) {
87 char *new_name
= dso__filename_with_chroot(dso
, dso__long_name(dso
));
89 if (new_name
&& filename__read_build_id(new_name
, dso__bid(dso
)) > 0) {
90 args
->have_build_id
= true;
91 dso__set_has_build_id(dso
);
95 nsinfo__mountns_exit(&nsc
);
99 bool dsos__read_build_ids(struct dsos
*dsos
, bool with_hits
)
101 struct dsos__read_build_ids_cb_args args
= {
102 .with_hits
= with_hits
,
103 .have_build_id
= false,
106 dsos__for_each_dso(dsos
, dsos__read_build_ids_cb
, &args
);
107 return args
.have_build_id
;
110 static int __dso__cmp_long_name(const char *long_name
, const struct dso_id
*id
,
113 int rc
= strcmp(long_name
, dso__long_name(b
));
114 return rc
?: dso_id__cmp(id
, dso__id_const(b
));
117 static int __dso__cmp_short_name(const char *short_name
, const struct dso_id
*id
,
120 int rc
= strcmp(short_name
, dso__short_name(b
));
121 return rc
?: dso_id__cmp(id
, dso__id_const(b
));
124 static int dsos__cmp_long_name_id_short_name(const void *va
, const void *vb
)
126 const struct dso
*a
= *((const struct dso
**)va
);
127 const struct dso
*b
= *((const struct dso
**)vb
);
128 int rc
= strcmp(dso__long_name(a
), dso__long_name(b
));
131 rc
= dso_id__cmp(dso__id_const(a
), dso__id_const(b
));
133 rc
= strcmp(dso__short_name(a
), dso__short_name(b
));
139 const char *long_name
;
140 const struct dso_id
*id
;
143 static int dsos__cmp_key_long_name_id(const void *vkey
, const void *vdso
)
145 const struct dsos__key
*key
= vkey
;
146 const struct dso
*dso
= *((const struct dso
**)vdso
);
148 return __dso__cmp_long_name(key
->long_name
, key
->id
, dso
);
152 * Find a matching entry and/or link current entry to RB tree.
153 * Either one of the dso or name parameter must be non-NULL or the
154 * function will not work.
156 static struct dso
*__dsos__find_by_longname_id(struct dsos
*dsos
,
158 const struct dso_id
*id
,
161 struct dsos__key key
= {
167 if (dsos
->dsos
== NULL
)
174 up_read(&dsos
->lock
);
175 down_write(&dsos
->lock
);
176 dso
= __dsos__find_by_longname_id(dsos
, name
, id
,
177 /*write_locked=*/true);
178 up_write(&dsos
->lock
);
179 down_read(&dsos
->lock
);
182 qsort(dsos
->dsos
, dsos
->cnt
, sizeof(struct dso
*),
183 dsos__cmp_long_name_id_short_name
);
187 res
= bsearch(&key
, dsos
->dsos
, dsos
->cnt
, sizeof(struct dso
*),
188 dsos__cmp_key_long_name_id
);
192 return dso__get(*res
);
195 int __dsos__add(struct dsos
*dsos
, struct dso
*dso
)
197 if (dsos
->cnt
== dsos
->allocated
) {
198 unsigned int to_allocate
= 2;
201 if (dsos
->allocated
> 0)
202 to_allocate
= dsos
->allocated
* 2;
203 temp
= realloc(dsos
->dsos
, sizeof(struct dso
*) * to_allocate
);
207 dsos
->allocated
= to_allocate
;
210 dsos
->dsos
[dsos
->cnt
++] = dso__get(dso
);
212 int low
= 0, high
= dsos
->cnt
- 1;
213 int insert
= dsos
->cnt
; /* Default to inserting at the end. */
215 while (low
<= high
) {
216 int mid
= low
+ (high
- low
) / 2;
217 int cmp
= dsos__cmp_long_name_id_short_name(&dsos
->dsos
[mid
], &dso
);
226 memmove(&dsos
->dsos
[insert
+ 1], &dsos
->dsos
[insert
],
227 (dsos
->cnt
- insert
) * sizeof(struct dso
*));
229 dsos
->dsos
[insert
] = dso__get(dso
);
231 dso__set_dsos(dso
, dsos
);
235 int dsos__add(struct dsos
*dsos
, struct dso
*dso
)
239 down_write(&dsos
->lock
);
240 ret
= __dsos__add(dsos
, dso
);
241 up_write(&dsos
->lock
);
245 struct dsos__find_id_cb_args
{
247 const struct dso_id
*id
;
251 static int dsos__find_id_cb(struct dso
*dso
, void *data
)
253 struct dsos__find_id_cb_args
*args
= data
;
255 if (__dso__cmp_short_name(args
->name
, args
->id
, dso
) == 0) {
256 args
->res
= dso__get(dso
);
263 static struct dso
*__dsos__find_id(struct dsos
*dsos
, const char *name
, const struct dso_id
*id
,
264 bool cmp_short
, bool write_locked
)
269 struct dsos__find_id_cb_args args
= {
275 __dsos__for_each_dso(dsos
, dsos__find_id_cb
, &args
);
278 res
= __dsos__find_by_longname_id(dsos
, name
, id
, write_locked
);
282 struct dso
*dsos__find(struct dsos
*dsos
, const char *name
, bool cmp_short
)
286 down_read(&dsos
->lock
);
287 res
= __dsos__find_id(dsos
, name
, NULL
, cmp_short
, /*write_locked=*/false);
288 up_read(&dsos
->lock
);
292 static void dso__set_basename(struct dso
*dso
)
297 if (perf_pid_map_tid(dso__long_name(dso
), &tid
)) {
298 if (asprintf(&base
, "[JIT] tid %d", tid
) < 0)
302 * basename() may modify path buffer, so we must pass
305 lname
= strdup(dso__long_name(dso
));
310 * basename() may return a pointer to internal
311 * storage which is reused in subsequent calls
312 * so copy the result.
314 base
= strdup(basename(lname
));
321 dso__set_short_name(dso
, base
, true);
324 static struct dso
*__dsos__addnew_id(struct dsos
*dsos
, const char *name
, const struct dso_id
*id
)
326 struct dso
*dso
= dso__new_id(name
, id
);
330 * The dsos lock is held on entry, so rename the dso before
331 * adding it to avoid needing to take the dsos lock again to say
332 * the array isn't sorted.
334 dso__set_basename(dso
);
335 __dsos__add(dsos
, dso
);
340 static struct dso
*__dsos__findnew_id(struct dsos
*dsos
, const char *name
, const struct dso_id
*id
)
342 struct dso
*dso
= __dsos__find_id(dsos
, name
, id
, false, /*write_locked=*/true);
344 if (dso
&& dso_id__empty(dso__id(dso
)) && !dso_id__empty(id
))
345 __dso__inject_id(dso
, id
);
347 return dso
? dso
: __dsos__addnew_id(dsos
, name
, id
);
350 struct dso
*dsos__findnew_id(struct dsos
*dsos
, const char *name
, const struct dso_id
*id
)
353 down_write(&dsos
->lock
);
354 dso
= __dsos__findnew_id(dsos
, name
, id
);
355 up_write(&dsos
->lock
);
359 struct dsos__fprintf_buildid_cb_args
{
361 bool (*skip
)(struct dso
*dso
, int parm
);
366 static int dsos__fprintf_buildid_cb(struct dso
*dso
, void *data
)
368 struct dsos__fprintf_buildid_cb_args
*args
= data
;
369 char sbuild_id
[SBUILD_ID_SIZE
];
371 if (args
->skip
&& args
->skip(dso
, args
->parm
))
373 build_id__sprintf(dso__bid(dso
), sbuild_id
);
374 args
->ret
+= fprintf(args
->fp
, "%-40s %s\n", sbuild_id
, dso__long_name(dso
));
378 size_t dsos__fprintf_buildid(struct dsos
*dsos
, FILE *fp
,
379 bool (*skip
)(struct dso
*dso
, int parm
), int parm
)
381 struct dsos__fprintf_buildid_cb_args args
= {
388 dsos__for_each_dso(dsos
, dsos__fprintf_buildid_cb
, &args
);
392 struct dsos__fprintf_cb_args
{
397 static int dsos__fprintf_cb(struct dso
*dso
, void *data
)
399 struct dsos__fprintf_cb_args
*args
= data
;
401 args
->ret
+= dso__fprintf(dso
, args
->fp
);
405 size_t dsos__fprintf(struct dsos
*dsos
, FILE *fp
)
407 struct dsos__fprintf_cb_args args
= {
412 dsos__for_each_dso(dsos
, dsos__fprintf_cb
, &args
);
416 static int dsos__hit_all_cb(struct dso
*dso
, void *data __maybe_unused
)
422 int dsos__hit_all(struct dsos
*dsos
)
424 return dsos__for_each_dso(dsos
, dsos__hit_all_cb
, NULL
);
427 struct dso
*dsos__findnew_module_dso(struct dsos
*dsos
,
428 struct machine
*machine
,
430 const char *filename
)
434 down_write(&dsos
->lock
);
436 dso
= __dsos__find_id(dsos
, m
->name
, NULL
, /*cmp_short=*/true, /*write_locked=*/true);
438 up_write(&dsos
->lock
);
442 * Failed to find the dso so create it. Change the name before adding it
443 * to the array, to avoid unnecessary sorts and potential locking
446 dso
= dso__new_id(m
->name
, /*id=*/NULL
);
448 up_write(&dsos
->lock
);
451 dso__set_basename(dso
);
452 dso__set_module_info(dso
, m
, machine
);
453 dso__set_long_name(dso
, strdup(filename
), true);
454 dso__set_kernel(dso
, DSO_SPACE__KERNEL
);
455 __dsos__add(dsos
, dso
);
457 up_write(&dsos
->lock
);
461 static int dsos__find_kernel_dso_cb(struct dso
*dso
, void *data
)
463 struct dso
**res
= data
;
465 * The cpumode passed to is_kernel_module is not the cpumode of *this*
466 * event. If we insist on passing correct cpumode to is_kernel_module,
467 * we should record the cpumode when we adding this dso to the linked
470 * However we don't really need passing correct cpumode. We know the
471 * correct cpumode must be kernel mode (if not, we should not link it
472 * onto kernel_dsos list).
474 * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.
475 * is_kernel_module() treats it as a kernel cpumode.
477 if (!dso__kernel(dso
) ||
478 is_kernel_module(dso__long_name(dso
), PERF_RECORD_MISC_CPUMODE_UNKNOWN
))
481 *res
= dso__get(dso
);
485 struct dso
*dsos__find_kernel_dso(struct dsos
*dsos
)
487 struct dso
*res
= NULL
;
489 dsos__for_each_dso(dsos
, dsos__find_kernel_dso_cb
, &res
);
493 int dsos__for_each_dso(struct dsos
*dsos
, int (*cb
)(struct dso
*dso
, void *data
), void *data
)
497 down_read(&dsos
->lock
);
498 err
= __dsos__for_each_dso(dsos
, cb
, data
);
499 up_read(&dsos
->lock
);