brintos

brintos / linux-shallow public Read only

0
0
Text · 11.2 KiB · e0998e2 Raw
502 lines · c
1// SPDX-License-Identifier: GPL-2.02#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_id13#include <unistd.h>14 15void dsos__init(struct dsos *dsos)16{17	init_rwsem(&dsos->lock);18 19	dsos->cnt = 0;20	dsos->allocated = 0;21	dsos->dsos = NULL;22	dsos->sorted = true;23}24 25static void dsos__purge(struct dsos *dsos)26{27	down_write(&dsos->lock);28 29	for (unsigned int i = 0; i < dsos->cnt; i++) {30		struct dso *dso = dsos->dsos[i];31 32		dso__set_dsos(dso, NULL);33		dso__put(dso);34	}35 36	zfree(&dsos->dsos);37	dsos->cnt = 0;38	dsos->allocated = 0;39	dsos->sorted = true;40 41	up_write(&dsos->lock);42}43 44void dsos__exit(struct dsos *dsos)45{46	dsos__purge(dsos);47	exit_rwsem(&dsos->lock);48}49 50 51static int __dsos__for_each_dso(struct dsos *dsos,52				int (*cb)(struct dso *dso, void *data),53				void *data)54{55	for (unsigned int i = 0; i < dsos->cnt; i++) {56		struct dso *dso = dsos->dsos[i];57		int err;58 59		err = cb(dso, data);60		if (err)61			return err;62	}63	return 0;64}65 66struct dsos__read_build_ids_cb_args {67	bool with_hits;68	bool have_build_id;69};70 71static int dsos__read_build_ids_cb(struct dso *dso, void *data)72{73	struct dsos__read_build_ids_cb_args *args = data;74	struct nscookie nsc;75 76	if (args->with_hits && !dso__hit(dso) && !dso__is_vdso(dso))77		return 0;78	if (dso__has_build_id(dso)) {79		args->have_build_id = true;80		return 0;81	}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));88 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);92		}93		free(new_name);94	}95	nsinfo__mountns_exit(&nsc);96	return 0;97}98 99bool dsos__read_build_ids(struct dsos *dsos, bool with_hits)100{101	struct dsos__read_build_ids_cb_args args = {102		.with_hits = with_hits,103		.have_build_id = false,104	};105 106	dsos__for_each_dso(dsos, dsos__read_build_ids_cb, &args);107	return args.have_build_id;108}109 110static int __dso__cmp_long_name(const char *long_name, const struct dso_id *id,111				const struct dso *b)112{113	int rc = strcmp(long_name, dso__long_name(b));114	return rc ?: dso_id__cmp(id, dso__id_const(b));115}116 117static int __dso__cmp_short_name(const char *short_name, const struct dso_id *id,118				 const struct dso *b)119{120	int rc = strcmp(short_name, dso__short_name(b));121	return rc ?: dso_id__cmp(id, dso__id_const(b));122}123 124static int dsos__cmp_long_name_id_short_name(const void *va, const void *vb)125{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));129 130	if (!rc) {131		rc = dso_id__cmp(dso__id_const(a), dso__id_const(b));132		if (!rc)133			rc = strcmp(dso__short_name(a), dso__short_name(b));134	}135	return rc;136}137 138struct dsos__key {139	const char *long_name;140	const struct dso_id *id;141};142 143static int dsos__cmp_key_long_name_id(const void *vkey, const void *vdso)144{145	const struct dsos__key *key = vkey;146	const struct dso *dso = *((const struct dso **)vdso);147 148	return __dso__cmp_long_name(key->long_name, key->id, dso);149}150 151/*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 the154 * function will not work.155 */156static struct dso *__dsos__find_by_longname_id(struct dsos *dsos,157					       const char *name,158					       const struct dso_id *id,159					       bool write_locked)160{161	struct dsos__key key = {162		.long_name = name,163		.id = id,164	};165	struct dso **res;166 167	if (dsos->dsos == NULL)168		return NULL;169 170	if (!dsos->sorted) {171		if (!write_locked) {172			struct dso *dso;173 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);180			return dso;181		}182		qsort(dsos->dsos, dsos->cnt, sizeof(struct dso *),183		      dsos__cmp_long_name_id_short_name);184		dsos->sorted = true;185	}186 187	res = bsearch(&key, dsos->dsos, dsos->cnt, sizeof(struct dso *),188		      dsos__cmp_key_long_name_id);189	if (!res)190		return NULL;191 192	return dso__get(*res);193}194 195int __dsos__add(struct dsos *dsos, struct dso *dso)196{197	if (dsos->cnt == dsos->allocated) {198		unsigned int to_allocate = 2;199		struct dso **temp;200 201		if (dsos->allocated > 0)202			to_allocate = dsos->allocated * 2;203		temp = realloc(dsos->dsos, sizeof(struct dso *) * to_allocate);204		if (!temp)205			return -ENOMEM;206		dsos->dsos = temp;207		dsos->allocated = to_allocate;208	}209	if (!dsos->sorted) {210		dsos->dsos[dsos->cnt++] = dso__get(dso);211	} else {212		int low = 0, high = dsos->cnt - 1;213		int insert = dsos->cnt; /* Default to inserting at the end. */214 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);218 219			if (cmp < 0) {220				low = mid + 1;221			} else {222				high = mid - 1;223				insert = mid;224			}225		}226		memmove(&dsos->dsos[insert + 1], &dsos->dsos[insert],227			(dsos->cnt - insert) * sizeof(struct dso *));228		dsos->cnt++;229		dsos->dsos[insert] = dso__get(dso);230	}231	dso__set_dsos(dso, dsos);232	return 0;233}234 235int dsos__add(struct dsos *dsos, struct dso *dso)236{237	int ret;238 239	down_write(&dsos->lock);240	ret = __dsos__add(dsos, dso);241	up_write(&dsos->lock);242	return ret;243}244 245struct dsos__find_id_cb_args {246	const char *name;247	const struct dso_id *id;248	struct dso *res;249};250 251static int dsos__find_id_cb(struct dso *dso, void *data)252{253	struct dsos__find_id_cb_args *args = data;254 255	if (__dso__cmp_short_name(args->name, args->id, dso) == 0) {256		args->res = dso__get(dso);257		return 1;258	}259	return 0;260 261}262 263static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, const struct dso_id *id,264				   bool cmp_short, bool write_locked)265{266	struct dso *res;267 268	if (cmp_short) {269		struct dsos__find_id_cb_args args = {270			.name = name,271			.id = id,272			.res = NULL,273		};274 275		__dsos__for_each_dso(dsos, dsos__find_id_cb, &args);276		return args.res;277	}278	res = __dsos__find_by_longname_id(dsos, name, id, write_locked);279	return res;280}281 282struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)283{284	struct dso *res;285 286	down_read(&dsos->lock);287	res = __dsos__find_id(dsos, name, NULL, cmp_short, /*write_locked=*/false);288	up_read(&dsos->lock);289	return res;290}291 292static void dso__set_basename(struct dso *dso)293{294	char *base, *lname;295	int tid;296 297	if (perf_pid_map_tid(dso__long_name(dso), &tid)) {298		if (asprintf(&base, "[JIT] tid %d", tid) < 0)299			return;300	} else {301	      /*302	       * basename() may modify path buffer, so we must pass303               * a copy.304               */305		lname = strdup(dso__long_name(dso));306		if (!lname)307			return;308 309		/*310		 * basename() may return a pointer to internal311		 * storage which is reused in subsequent calls312		 * so copy the result.313		 */314		base = strdup(basename(lname));315 316		free(lname);317 318		if (!base)319			return;320	}321	dso__set_short_name(dso, base, true);322}323 324static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, const struct dso_id *id)325{326	struct dso *dso = dso__new_id(name, id);327 328	if (dso != NULL) {329		/*330		 * The dsos lock is held on entry, so rename the dso before331		 * adding it to avoid needing to take the dsos lock again to say332		 * the array isn't sorted.333		 */334		dso__set_basename(dso);335		__dsos__add(dsos, dso);336	}337	return dso;338}339 340static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name, const struct dso_id *id)341{342	struct dso *dso = __dsos__find_id(dsos, name, id, false, /*write_locked=*/true);343 344	if (dso && dso_id__empty(dso__id(dso)) && !dso_id__empty(id))345		__dso__inject_id(dso, id);346 347	return dso ? dso : __dsos__addnew_id(dsos, name, id);348}349 350struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, const struct dso_id *id)351{352	struct dso *dso;353	down_write(&dsos->lock);354	dso = __dsos__findnew_id(dsos, name, id);355	up_write(&dsos->lock);356	return dso;357}358 359struct dsos__fprintf_buildid_cb_args {360	FILE *fp;361	bool (*skip)(struct dso *dso, int parm);362	int parm;363	size_t ret;364};365 366static int dsos__fprintf_buildid_cb(struct dso *dso, void *data)367{368	struct dsos__fprintf_buildid_cb_args *args = data;369	char sbuild_id[SBUILD_ID_SIZE];370 371	if (args->skip && args->skip(dso, args->parm))372		return 0;373	build_id__sprintf(dso__bid(dso), sbuild_id);374	args->ret += fprintf(args->fp, "%-40s %s\n", sbuild_id, dso__long_name(dso));375	return 0;376}377 378size_t dsos__fprintf_buildid(struct dsos *dsos, FILE *fp,379			       bool (*skip)(struct dso *dso, int parm), int parm)380{381	struct dsos__fprintf_buildid_cb_args args = {382		.fp = fp,383		.skip = skip,384		.parm = parm,385		.ret = 0,386	};387 388	dsos__for_each_dso(dsos, dsos__fprintf_buildid_cb, &args);389	return args.ret;390}391 392struct dsos__fprintf_cb_args {393	FILE *fp;394	size_t ret;395};396 397static int dsos__fprintf_cb(struct dso *dso, void *data)398{399	struct dsos__fprintf_cb_args *args = data;400 401	args->ret += dso__fprintf(dso, args->fp);402	return 0;403}404 405size_t dsos__fprintf(struct dsos *dsos, FILE *fp)406{407	struct dsos__fprintf_cb_args args = {408		.fp = fp,409		.ret = 0,410	};411 412	dsos__for_each_dso(dsos, dsos__fprintf_cb, &args);413	return args.ret;414}415 416static int dsos__hit_all_cb(struct dso *dso, void *data __maybe_unused)417{418	dso__set_hit(dso);419	return 0;420}421 422int dsos__hit_all(struct dsos *dsos)423{424	return dsos__for_each_dso(dsos, dsos__hit_all_cb, NULL);425}426 427struct dso *dsos__findnew_module_dso(struct dsos *dsos,428				     struct machine *machine,429				     struct kmod_path *m,430				     const char *filename)431{432	struct dso *dso;433 434	down_write(&dsos->lock);435 436	dso = __dsos__find_id(dsos, m->name, NULL, /*cmp_short=*/true, /*write_locked=*/true);437	if (dso) {438		up_write(&dsos->lock);439		return dso;440	}441	/*442	 * Failed to find the dso so create it. Change the name before adding it443	 * to the array, to avoid unnecessary sorts and potential locking444	 * issues.445	 */446	dso = dso__new_id(m->name, /*id=*/NULL);447	if (!dso) {448		up_write(&dsos->lock);449		return NULL;450	}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);456 457	up_write(&dsos->lock);458	return dso;459}460 461static int dsos__find_kernel_dso_cb(struct dso *dso, void *data)462{463	struct dso **res = data;464	/*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 linked468	 * list.469	 *470	 * However we don't really need passing correct cpumode.  We know the471	 * correct cpumode must be kernel mode (if not, we should not link it472	 * onto kernel_dsos list).473	 *474	 * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.475	 * is_kernel_module() treats it as a kernel cpumode.476	 */477	if (!dso__kernel(dso) ||478	    is_kernel_module(dso__long_name(dso), PERF_RECORD_MISC_CPUMODE_UNKNOWN))479		return 0;480 481	*res = dso__get(dso);482	return 1;483}484 485struct dso *dsos__find_kernel_dso(struct dsos *dsos)486{487	struct dso *res = NULL;488 489	dsos__for_each_dso(dsos, dsos__find_kernel_dso_cb, &res);490	return res;491}492 493int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data)494{495	int err;496 497	down_read(&dsos->lock);498	err = __dsos__for_each_dso(dsos, cb, data);499	up_read(&dsos->lock);500	return err;501}502