diff options
Diffstat (limited to 'tools/perf/builtin-inject.c')
| -rw-r--r-- | tools/perf/builtin-inject.c | 203 | 
1 files changed, 162 insertions, 41 deletions
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 6d2f410d773a..452a75fe68e5 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -10,6 +10,7 @@  #include "util/color.h"  #include "util/dso.h" +#include "util/vdso.h"  #include "util/evlist.h"  #include "util/evsel.h"  #include "util/map.h" @@ -23,9 +24,11 @@  #include "util/symbol.h"  #include "util/synthetic-events.h"  #include "util/thread.h" -#include <linux/err.h> +#include "util/namespaces.h" +#include <linux/err.h>  #include <subcmd/parse-options.h> +#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */  #include <linux/list.h>  #include <errno.h> @@ -35,6 +38,7 @@ struct perf_inject {  	struct perf_tool	tool;  	struct perf_session	*session;  	bool			build_ids; +	bool			build_id_all;  	bool			sched_stat;  	bool			have_auxtrace;  	bool			strip; @@ -54,6 +58,9 @@ struct event_entry {  	union perf_event event[];  }; +static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, +				struct machine *machine, u8 cpumode, u32 flags); +  static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)  {  	ssize_t size; @@ -97,6 +104,13 @@ static int perf_event__repipe_op2_synth(struct perf_session *session,  	return perf_event__repipe_synth(session->tool, event);  } +static int perf_event__repipe_op4_synth(struct perf_session *session, +					union perf_event *event, +					u64 data __maybe_unused) +{ +	return perf_event__repipe_synth(session->tool, event); +} +  static int perf_event__repipe_attr(struct perf_tool *tool,  				   union perf_event *event,  				   struct evlist **pevlist) @@ -115,6 +129,13 @@ static int perf_event__repipe_attr(struct perf_tool *tool,  	return perf_event__repipe_synth(tool, event);  } +static int perf_event__repipe_event_update(struct perf_tool *tool, +					   union perf_event *event, +					   struct evlist **pevlist __maybe_unused) +{ +	return perf_event__repipe_synth(tool, event); +} +  #ifdef HAVE_AUXTRACE_SUPPORT  static int copy_bytes(struct perf_inject *inject, int fd, off_t size) @@ -303,6 +324,68 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,  }  #endif +static struct dso *findnew_dso(int pid, int tid, const char *filename, +			       struct dso_id *id, struct machine *machine) +{ +	struct thread *thread; +	struct nsinfo *nsi = NULL; +	struct nsinfo *nnsi; +	struct dso *dso; +	bool vdso; + +	thread = machine__findnew_thread(machine, pid, tid); +	if (thread == NULL) { +		pr_err("cannot find or create a task %d/%d.\n", tid, pid); +		return NULL; +	} + +	vdso = is_vdso_map(filename); +	nsi = nsinfo__get(thread->nsinfo); + +	if (vdso) { +		/* The vdso maps are always on the host and not the +		 * container.  Ensure that we don't use setns to look +		 * them up. +		 */ +		nnsi = nsinfo__copy(nsi); +		if (nnsi) { +			nsinfo__put(nsi); +			nnsi->need_setns = false; +			nsi = nnsi; +		} +		dso = machine__findnew_vdso(machine, thread); +	} else { +		dso = machine__findnew_dso_id(machine, filename, id); +	} + +	if (dso) +		dso->nsinfo = nsi; +	else +		nsinfo__put(nsi); + +	thread__put(thread); +	return dso; +} + +static int perf_event__repipe_buildid_mmap(struct perf_tool *tool, +					   union perf_event *event, +					   struct perf_sample *sample, +					   struct machine *machine) +{ +	struct dso *dso; + +	dso = findnew_dso(event->mmap.pid, event->mmap.tid, +			  event->mmap.filename, NULL, machine); + +	if (dso && !dso->hit) { +		dso->hit = 1; +		dso__inject_build_id(dso, tool, machine, sample->cpumode, 0); +		dso__put(dso); +	} + +	return perf_event__repipe(tool, event, sample, machine); +} +  static int perf_event__repipe_mmap2(struct perf_tool *tool,  				   union perf_event *event,  				   struct perf_sample *sample, @@ -341,6 +424,34 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,  }  #endif +static int perf_event__repipe_buildid_mmap2(struct perf_tool *tool, +					    union perf_event *event, +					    struct perf_sample *sample, +					    struct machine *machine) +{ +	struct dso_id dso_id = { +		.maj = event->mmap2.maj, +		.min = event->mmap2.min, +		.ino = event->mmap2.ino, +		.ino_generation = event->mmap2.ino_generation, +	}; +	struct dso *dso; + +	dso = findnew_dso(event->mmap2.pid, event->mmap2.tid, +			  event->mmap2.filename, &dso_id, machine); + +	if (dso && !dso->hit) { +		dso->hit = 1; +		dso__inject_build_id(dso, tool, machine, sample->cpumode, +				     event->mmap2.flags); +		dso__put(dso); +	} + +	perf_event__repipe(tool, event, sample, machine); + +	return 0; +} +  static int perf_event__repipe_fork(struct perf_tool *tool,  				   union perf_event *event,  				   struct perf_sample *sample, @@ -405,34 +516,36 @@ static int perf_event__repipe_tracing_data(struct perf_session *session,  static int dso__read_build_id(struct dso *dso)  { +	struct nscookie nsc; +  	if (dso->has_build_id)  		return 0; -	if (filename__read_build_id(dso->long_name, dso->build_id, -				    sizeof(dso->build_id)) > 0) { +	nsinfo__mountns_enter(dso->nsinfo, &nsc); +	if (filename__read_build_id(dso->long_name, &dso->bid) > 0)  		dso->has_build_id = true; -		return 0; -	} +	nsinfo__mountns_exit(&nsc); -	return -1; +	return dso->has_build_id ? 0 : -1;  }  static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, -				struct machine *machine) +				struct machine *machine, u8 cpumode, u32 flags)  { -	u16 misc = PERF_RECORD_MISC_USER;  	int err; +	if (is_anon_memory(dso->long_name) || flags & MAP_HUGETLB) +		return 0; +	if (is_no_dso_memory(dso->long_name)) +		return 0; +  	if (dso__read_build_id(dso) < 0) {  		pr_debug("no build_id found for %s\n", dso->long_name);  		return -1;  	} -	if (dso->kernel) -		misc = PERF_RECORD_MISC_KERNEL; - -	err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe, -					      machine); +	err = perf_event__synthesize_build_id(tool, dso, cpumode, +					      perf_event__repipe, machine);  	if (err) {  		pr_err("Can't synthesize build_id event for %s\n", dso->long_name);  		return -1; @@ -441,11 +554,10 @@ static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,  	return 0;  } -static int perf_event__inject_buildid(struct perf_tool *tool, -				      union perf_event *event, -				      struct perf_sample *sample, -				      struct evsel *evsel __maybe_unused, -				      struct machine *machine) +int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, +			       struct perf_sample *sample, +			       struct evsel *evsel __maybe_unused, +			       struct machine *machine)  {  	struct addr_location al;  	struct thread *thread; @@ -460,19 +572,8 @@ static int perf_event__inject_buildid(struct perf_tool *tool,  	if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {  		if (!al.map->dso->hit) {  			al.map->dso->hit = 1; -			if (map__load(al.map) >= 0) { -				dso__inject_build_id(al.map->dso, tool, machine); -				/* -				 * If this fails, too bad, let the other side -				 * account this as unresolved. -				 */ -			} else { -#ifdef HAVE_LIBELF_SUPPORT -				pr_warning("no symbols found in %s, maybe " -					   "install a debug package?\n", -					   al.map->dso->long_name); -#endif -			} +			dso__inject_build_id(al.map->dso, tool, machine, +					     sample->cpumode, al.map->flags);  		}  	} @@ -606,7 +707,7 @@ static int __cmd_inject(struct perf_inject *inject)  	signal(SIGINT, sig_handler);  	if (inject->build_ids || inject->sched_stat || -	    inject->itrace_synth_opts.set) { +	    inject->itrace_synth_opts.set || inject->build_id_all) {  		inject->tool.mmap	  = perf_event__repipe_mmap;  		inject->tool.mmap2	  = perf_event__repipe_mmap2;  		inject->tool.fork	  = perf_event__repipe_fork; @@ -615,7 +716,10 @@ static int __cmd_inject(struct perf_inject *inject)  	output_data_offset = session->header.data_offset; -	if (inject->build_ids) { +	if (inject->build_id_all) { +		inject->tool.mmap	  = perf_event__repipe_buildid_mmap; +		inject->tool.mmap2	  = perf_event__repipe_buildid_mmap2; +	} else if (inject->build_ids) {  		inject->tool.sample = perf_event__inject_buildid;  	} else if (inject->sched_stat) {  		struct evsel *evsel; @@ -708,9 +812,12 @@ int cmd_inject(int argc, const char **argv)  	struct perf_inject inject = {  		.tool = {  			.sample		= perf_event__repipe_sample, +			.read		= perf_event__repipe_sample,  			.mmap		= perf_event__repipe,  			.mmap2		= perf_event__repipe,  			.comm		= perf_event__repipe, +			.namespaces	= perf_event__repipe, +			.cgroup		= perf_event__repipe,  			.fork		= perf_event__repipe,  			.exit		= perf_event__repipe,  			.lost		= perf_event__repipe, @@ -718,19 +825,28 @@ int cmd_inject(int argc, const char **argv)  			.aux		= perf_event__repipe,  			.itrace_start	= perf_event__repipe,  			.context_switch	= perf_event__repipe, -			.read		= perf_event__repipe_sample,  			.throttle	= perf_event__repipe,  			.unthrottle	= perf_event__repipe, +			.ksymbol	= perf_event__repipe, +			.bpf		= perf_event__repipe, +			.text_poke	= perf_event__repipe,  			.attr		= perf_event__repipe_attr, +			.event_update	= perf_event__repipe_event_update,  			.tracing_data	= perf_event__repipe_op2_synth, -			.auxtrace_info	= perf_event__repipe_op2_synth, -			.auxtrace	= perf_event__repipe_auxtrace, -			.auxtrace_error	= perf_event__repipe_op2_synth, -			.time_conv	= perf_event__repipe_op2_synth,  			.finished_round	= perf_event__repipe_oe_synth,  			.build_id	= perf_event__repipe_op2_synth,  			.id_index	= perf_event__repipe_op2_synth, +			.auxtrace_info	= perf_event__repipe_op2_synth, +			.auxtrace_error	= perf_event__repipe_op2_synth, +			.time_conv	= perf_event__repipe_op2_synth, +			.thread_map	= perf_event__repipe_op2_synth, +			.cpu_map	= perf_event__repipe_op2_synth, +			.stat_config	= perf_event__repipe_op2_synth, +			.stat		= perf_event__repipe_op2_synth, +			.stat_round	= perf_event__repipe_op2_synth,  			.feature	= perf_event__repipe_op2_synth, +			.compressed	= perf_event__repipe_op4_synth, +			.auxtrace	= perf_event__repipe_auxtrace,  		},  		.input_name  = "-",  		.samples = LIST_HEAD_INIT(inject.samples), @@ -747,6 +863,8 @@ int cmd_inject(int argc, const char **argv)  	struct option options[] = {  		OPT_BOOLEAN('b', "build-ids", &inject.build_ids,  			    "Inject build-ids into the output stream"), +		OPT_BOOLEAN(0, "buildid-all", &inject.build_id_all, +			    "Inject build-ids of all DSOs into the output stream"),  		OPT_STRING('i', "input", &inject.input_name, "file",  			   "input file name"),  		OPT_STRING('o', "output", &inject.output.path, "file", @@ -795,8 +913,6 @@ int cmd_inject(int argc, const char **argv)  		return -1;  	} -	inject.tool.ordered_events = inject.sched_stat; -  	data.path = inject.input_name;  	inject.session = perf_session__new(&data, true, &inject.tool);  	if (IS_ERR(inject.session)) @@ -805,7 +921,7 @@ int cmd_inject(int argc, const char **argv)  	if (zstd_init(&(inject.session->zstd_data), 0) < 0)  		pr_warning("Decompression initialization failed.\n"); -	if (inject.build_ids) { +	if (inject.build_ids && !inject.build_id_all) {  		/*  		 * to make sure the mmap records are ordered correctly  		 * and so that the correct especially due to jitted code @@ -815,6 +931,11 @@ int cmd_inject(int argc, const char **argv)  		inject.tool.ordered_events = true;  		inject.tool.ordering_requires_timestamps = true;  	} + +	if (inject.sched_stat) { +		inject.tool.ordered_events = true; +	} +  #ifdef HAVE_JITDUMP  	if (inject.jit_mode) {  		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;  | 
