xref: /linux/tools/perf/util/dsos.c (revision 173b0b5b0e865348684c02bd9cb1d22b5d46e458)
1 // SPDX-License-Identifier: GPL-2.0
2 #include "debug.h"
3 #include "dsos.h"
4 #include "dso.h"
5 #include "util.h"
6 #include "vdso.h"
7 #include "namespaces.h"
8 #include <errno.h>
9 #include <libgen.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <symbol.h> // filename__read_build_id
13 #include <unistd.h>
14 
15 void dsos__init(struct dsos *dsos)
16 {
17 	INIT_LIST_HEAD(&dsos->head);
18 	dsos->root = RB_ROOT;
19 	init_rwsem(&dsos->lock);
20 }
21 
22 static void dsos__purge(struct dsos *dsos)
23 {
24 	struct dso *pos, *n;
25 
26 	down_write(&dsos->lock);
27 
28 	list_for_each_entry_safe(pos, n, &dsos->head, node) {
29 		RB_CLEAR_NODE(&pos->rb_node);
30 		pos->root = NULL;
31 		list_del_init(&pos->node);
32 		dso__put(pos);
33 	}
34 
35 	up_write(&dsos->lock);
36 }
37 
38 void dsos__exit(struct dsos *dsos)
39 {
40 	dsos__purge(dsos);
41 	exit_rwsem(&dsos->lock);
42 }
43 
44 
45 static int __dsos__for_each_dso(struct dsos *dsos,
46 				int (*cb)(struct dso *dso, void *data),
47 				void *data)
48 {
49 	struct dso *dso;
50 
51 	list_for_each_entry(dso, &dsos->head, node) {
52 		int err;
53 
54 		err = cb(dso, data);
55 		if (err)
56 			return err;
57 	}
58 	return 0;
59 }
60 
61 struct dsos__read_build_ids_cb_args {
62 	bool with_hits;
63 	bool have_build_id;
64 };
65 
66 static int dsos__read_build_ids_cb(struct dso *dso, void *data)
67 {
68 	struct dsos__read_build_ids_cb_args *args = data;
69 	struct nscookie nsc;
70 
71 	if (args->with_hits && !dso->hit && !dso__is_vdso(dso))
72 		return 0;
73 	if (dso->has_build_id) {
74 		args->have_build_id = true;
75 		return 0;
76 	}
77 	nsinfo__mountns_enter(dso->nsinfo, &nsc);
78 	if (filename__read_build_id(dso->long_name, &dso->bid) > 0) {
79 		args->have_build_id = true;
80 		dso->has_build_id = true;
81 	} else if (errno == ENOENT && dso->nsinfo) {
82 		char *new_name = dso__filename_with_chroot(dso, dso->long_name);
83 
84 		if (new_name && filename__read_build_id(new_name, &dso->bid) > 0) {
85 			args->have_build_id = true;
86 			dso->has_build_id = true;
87 		}
88 		free(new_name);
89 	}
90 	nsinfo__mountns_exit(&nsc);
91 	return 0;
92 }
93 
94 bool dsos__read_build_ids(struct dsos *dsos, bool with_hits)
95 {
96 	struct dsos__read_build_ids_cb_args args = {
97 		.with_hits = with_hits,
98 		.have_build_id = false,
99 	};
100 
101 	dsos__for_each_dso(dsos, dsos__read_build_ids_cb, &args);
102 	return args.have_build_id;
103 }
104 
105 static int __dso__cmp_long_name(const char *long_name, struct dso_id *id, struct dso *b)
106 {
107 	int rc = strcmp(long_name, b->long_name);
108 	return rc ?: dso_id__cmp(id, &b->id);
109 }
110 
111 static int __dso__cmp_short_name(const char *short_name, struct dso_id *id, struct dso *b)
112 {
113 	int rc = strcmp(short_name, b->short_name);
114 	return rc ?: dso_id__cmp(id, &b->id);
115 }
116 
117 static int dso__cmp_short_name(struct dso *a, struct dso *b)
118 {
119 	return __dso__cmp_short_name(a->short_name, &a->id, b);
120 }
121 
122 /*
123  * Find a matching entry and/or link current entry to RB tree.
124  * Either one of the dso or name parameter must be non-NULL or the
125  * function will not work.
126  */
127 struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso *dso,
128 						const char *name, struct dso_id *id)
129 {
130 	struct rb_node **p = &root->rb_node;
131 	struct rb_node  *parent = NULL;
132 
133 	if (!name)
134 		name = dso->long_name;
135 
136 	/*
137 	 * Find node with the matching name
138 	 */
139 	while (*p) {
140 		struct dso *this = rb_entry(*p, struct dso, rb_node);
141 		int rc = __dso__cmp_long_name(name, id, this);
142 
143 		parent = *p;
144 		if (rc == 0) {
145 			/*
146 			 * In case the new DSO is a duplicate of an existing
147 			 * one, print a one-time warning & put the new entry
148 			 * at the end of the list of duplicates.
149 			 */
150 			if (!dso || (dso == this))
151 				return dso__get(this);	/* Find matching dso */
152 			/*
153 			 * The core kernel DSOs may have duplicated long name.
154 			 * In this case, the short name should be different.
155 			 * Comparing the short names to differentiate the DSOs.
156 			 */
157 			rc = dso__cmp_short_name(dso, this);
158 			if (rc == 0) {
159 				pr_err("Duplicated dso name: %s\n", name);
160 				return NULL;
161 			}
162 		}
163 		if (rc < 0)
164 			p = &parent->rb_left;
165 		else
166 			p = &parent->rb_right;
167 	}
168 	if (dso) {
169 		/* Add new node and rebalance tree */
170 		rb_link_node(&dso->rb_node, parent, p);
171 		rb_insert_color(&dso->rb_node, root);
172 		dso->root = root;
173 	}
174 	return NULL;
175 }
176 
177 void __dsos__add(struct dsos *dsos, struct dso *dso)
178 {
179 	list_add_tail(&dso->node, &dsos->head);
180 	__dsos__findnew_link_by_longname_id(&dsos->root, dso, NULL, &dso->id);
181 	/*
182 	 * It is now in the linked list, grab a reference, then garbage collect
183 	 * this when needing memory, by looking at LRU dso instances in the
184 	 * list with atomic_read(&dso->refcnt) == 1, i.e. no references
185 	 * anywhere besides the one for the list, do, under a lock for the
186 	 * list: remove it from the list, then a dso__put(), that probably will
187 	 * be the last and will then call dso__delete(), end of life.
188 	 *
189 	 * That, or at the end of the 'struct machine' lifetime, when all
190 	 * 'struct dso' instances will be removed from the list, in
191 	 * dsos__exit(), if they have no other reference from some other data
192 	 * structure.
193 	 *
194 	 * E.g.: after processing a 'perf.data' file and storing references
195 	 * to objects instantiated while processing events, we will have
196 	 * references to the 'thread', 'map', 'dso' structs all from 'struct
197 	 * hist_entry' instances, but we may not need anything not referenced,
198 	 * so we might as well call machines__exit()/machines__delete() and
199 	 * garbage collect it.
200 	 */
201 	dso__get(dso);
202 }
203 
204 void dsos__add(struct dsos *dsos, struct dso *dso)
205 {
206 	down_write(&dsos->lock);
207 	__dsos__add(dsos, dso);
208 	up_write(&dsos->lock);
209 }
210 
211 static struct dso *__dsos__findnew_by_longname_id(struct rb_root *root, const char *name, struct dso_id *id)
212 {
213 	return __dsos__findnew_link_by_longname_id(root, NULL, name, id);
214 }
215 
216 struct dsos__find_id_cb_args {
217 	const char *name;
218 	struct dso_id *id;
219 	struct dso *res;
220 };
221 
222 static int dsos__find_id_cb(struct dso *dso, void *data)
223 {
224 	struct dsos__find_id_cb_args *args = data;
225 
226 	if (__dso__cmp_short_name(args->name, args->id, dso) == 0) {
227 		args->res = dso__get(dso);
228 		return 1;
229 	}
230 	return 0;
231 
232 }
233 
234 static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, struct dso_id *id, bool cmp_short)
235 {
236 	struct dso *res;
237 
238 	if (cmp_short) {
239 		struct dsos__find_id_cb_args args = {
240 			.name = name,
241 			.id = id,
242 			.res = NULL,
243 		};
244 
245 		__dsos__for_each_dso(dsos, dsos__find_id_cb, &args);
246 		return args.res;
247 	}
248 	res = __dsos__findnew_by_longname_id(&dsos->root, name, id);
249 	return res;
250 }
251 
252 struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
253 {
254 	struct dso *res;
255 
256 	down_read(&dsos->lock);
257 	res = __dsos__find_id(dsos, name, NULL, cmp_short);
258 	up_read(&dsos->lock);
259 	return res;
260 }
261 
262 static void dso__set_basename(struct dso *dso)
263 {
264 	char *base, *lname;
265 	int tid;
266 
267 	if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) {
268 		if (asprintf(&base, "[JIT] tid %d", tid) < 0)
269 			return;
270 	} else {
271 	      /*
272 	       * basename() may modify path buffer, so we must pass
273                * a copy.
274                */
275 		lname = strdup(dso->long_name);
276 		if (!lname)
277 			return;
278 
279 		/*
280 		 * basename() may return a pointer to internal
281 		 * storage which is reused in subsequent calls
282 		 * so copy the result.
283 		 */
284 		base = strdup(basename(lname));
285 
286 		free(lname);
287 
288 		if (!base)
289 			return;
290 	}
291 	dso__set_short_name(dso, base, true);
292 }
293 
294 static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
295 {
296 	struct dso *dso = dso__new_id(name, id);
297 
298 	if (dso != NULL) {
299 		__dsos__add(dsos, dso);
300 		dso__set_basename(dso);
301 	}
302 	return dso;
303 }
304 
305 struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
306 {
307 	return __dsos__addnew_id(dsos, name, NULL);
308 }
309 
310 static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
311 {
312 	struct dso *dso = __dsos__find_id(dsos, name, id, false);
313 
314 	if (dso && dso_id__empty(&dso->id) && !dso_id__empty(id))
315 		dso__inject_id(dso, id);
316 
317 	return dso ? dso : __dsos__addnew_id(dsos, name, id);
318 }
319 
320 struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id)
321 {
322 	struct dso *dso;
323 	down_write(&dsos->lock);
324 	dso = __dsos__findnew_id(dsos, name, id);
325 	up_write(&dsos->lock);
326 	return dso;
327 }
328 
329 struct dsos__fprintf_buildid_cb_args {
330 	FILE *fp;
331 	bool (*skip)(struct dso *dso, int parm);
332 	int parm;
333 	size_t ret;
334 };
335 
336 static int dsos__fprintf_buildid_cb(struct dso *dso, void *data)
337 {
338 	struct dsos__fprintf_buildid_cb_args *args = data;
339 	char sbuild_id[SBUILD_ID_SIZE];
340 
341 	if (args->skip && args->skip(dso, args->parm))
342 		return 0;
343 	build_id__sprintf(&dso->bid, sbuild_id);
344 	args->ret += fprintf(args->fp, "%-40s %s\n", sbuild_id, dso->long_name);
345 	return 0;
346 }
347 
348 size_t dsos__fprintf_buildid(struct dsos *dsos, FILE *fp,
349 			       bool (*skip)(struct dso *dso, int parm), int parm)
350 {
351 	struct dsos__fprintf_buildid_cb_args args = {
352 		.fp = fp,
353 		.skip = skip,
354 		.parm = parm,
355 		.ret = 0,
356 	};
357 
358 	dsos__for_each_dso(dsos, dsos__fprintf_buildid_cb, &args);
359 	return args.ret;
360 }
361 
362 struct dsos__fprintf_cb_args {
363 	FILE *fp;
364 	size_t ret;
365 };
366 
367 static int dsos__fprintf_cb(struct dso *dso, void *data)
368 {
369 	struct dsos__fprintf_cb_args *args = data;
370 
371 	args->ret += dso__fprintf(dso, args->fp);
372 	return 0;
373 }
374 
375 size_t dsos__fprintf(struct dsos *dsos, FILE *fp)
376 {
377 	struct dsos__fprintf_cb_args args = {
378 		.fp = fp,
379 		.ret = 0,
380 	};
381 
382 	dsos__for_each_dso(dsos, dsos__fprintf_cb, &args);
383 	return args.ret;
384 }
385 
386 static int dsos__hit_all_cb(struct dso *dso, void *data __maybe_unused)
387 {
388 	dso->hit = true;
389 	return 0;
390 }
391 
392 int dsos__hit_all(struct dsos *dsos)
393 {
394 	return dsos__for_each_dso(dsos, dsos__hit_all_cb, NULL);
395 }
396 
397 struct dso *dsos__findnew_module_dso(struct dsos *dsos,
398 				     struct machine *machine,
399 				     struct kmod_path *m,
400 				     const char *filename)
401 {
402 	struct dso *dso;
403 
404 	down_write(&dsos->lock);
405 
406 	dso = __dsos__find_id(dsos, m->name, NULL, /*cmp_short=*/true);
407 	if (!dso) {
408 		dso = __dsos__addnew(dsos, m->name);
409 		if (dso == NULL)
410 			goto out_unlock;
411 
412 		dso__set_module_info(dso, m, machine);
413 		dso__set_long_name(dso, strdup(filename), true);
414 		dso->kernel = DSO_SPACE__KERNEL;
415 	}
416 
417 out_unlock:
418 	up_write(&dsos->lock);
419 	return dso;
420 }
421 
422 static int dsos__find_kernel_dso_cb(struct dso *dso, void *data)
423 {
424 	struct dso **res = data;
425 	/*
426 	 * The cpumode passed to is_kernel_module is not the cpumode of *this*
427 	 * event. If we insist on passing correct cpumode to is_kernel_module,
428 	 * we should record the cpumode when we adding this dso to the linked
429 	 * list.
430 	 *
431 	 * However we don't really need passing correct cpumode.  We know the
432 	 * correct cpumode must be kernel mode (if not, we should not link it
433 	 * onto kernel_dsos list).
434 	 *
435 	 * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.
436 	 * is_kernel_module() treats it as a kernel cpumode.
437 	 */
438 	if (!dso->kernel ||
439 	    is_kernel_module(dso->long_name, PERF_RECORD_MISC_CPUMODE_UNKNOWN))
440 		return 0;
441 
442 	*res = dso__get(dso);
443 	return 1;
444 }
445 
446 struct dso *dsos__find_kernel_dso(struct dsos *dsos)
447 {
448 	struct dso *res = NULL;
449 
450 	dsos__for_each_dso(dsos, dsos__find_kernel_dso_cb, &res);
451 	return res;
452 }
453 
454 int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data)
455 {
456 	int err;
457 
458 	down_read(&dsos->lock);
459 	err = __dsos__for_each_dso(dsos, cb, data);
460 	up_read(&dsos->lock);
461 	return err;
462 }
463