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