xref: /openbmc/linux/tools/perf/builtin-inject.c (revision 892d00fb)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2454c407eSTom Zanussi /*
3454c407eSTom Zanussi  * builtin-inject.c
4454c407eSTom Zanussi  *
5454c407eSTom Zanussi  * Builtin inject command: Examine the live mode (stdin) event stream
6454c407eSTom Zanussi  * and repipe it to stdout while optionally injecting additional
7454c407eSTom Zanussi  * events into it.
8454c407eSTom Zanussi  */
9454c407eSTom Zanussi #include "builtin.h"
10454c407eSTom Zanussi 
1126a031e1SAndrew Vagin #include "util/color.h"
124a3cec84SArnaldo Carvalho de Melo #include "util/dso.h"
1327c9c342SNamhyung Kim #include "util/vdso.h"
1426a031e1SAndrew Vagin #include "util/evlist.h"
1526a031e1SAndrew Vagin #include "util/evsel.h"
161101f69aSArnaldo Carvalho de Melo #include "util/map.h"
17454c407eSTom Zanussi #include "util/session.h"
1845694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
19454c407eSTom Zanussi #include "util/debug.h"
2054a3cf59SAndrew Vagin #include "util/build-id.h"
21f5fc1412SJiri Olsa #include "util/data.h"
220f0aa5e0SAdrian Hunter #include "util/auxtrace.h"
239b07e27fSStephane Eranian #include "util/jit.h"
248012243eSRaul Silvera #include "util/string2.h"
25daecf9e0SArnaldo Carvalho de Melo #include "util/symbol.h"
26ea49e01cSArnaldo Carvalho de Melo #include "util/synthetic-events.h"
27e7ff8920SArnaldo Carvalho de Melo #include "util/thread.h"
28336c95b2SNamhyung Kim #include "util/namespaces.h"
2975d48c56SNamhyung Kim #include "util/util.h"
3097406a7eSAdrian Hunter #include "util/tsc.h"
31454c407eSTom Zanussi 
32180b3d06SAdrian Hunter #include <internal/lib.h>
33180b3d06SAdrian Hunter 
34e7b60c5aSNamhyung Kim #include <linux/err.h>
354b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
36e7b60c5aSNamhyung Kim #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
37454c407eSTom Zanussi 
3826a031e1SAndrew Vagin #include <linux/list.h>
3983d7f5f1SAdrian Hunter #include <linux/string.h>
4097406a7eSAdrian Hunter #include <linux/zalloc.h>
4197406a7eSAdrian Hunter #include <linux/hash.h>
428012243eSRaul Silvera #include <ctype.h>
43a43783aeSArnaldo Carvalho de Melo #include <errno.h>
449607ad3aSArnaldo Carvalho de Melo #include <signal.h>
4597406a7eSAdrian Hunter #include <inttypes.h>
4697406a7eSAdrian Hunter 
4797406a7eSAdrian Hunter struct guest_event {
4897406a7eSAdrian Hunter 	struct perf_sample		sample;
4997406a7eSAdrian Hunter 	union perf_event		*event;
50*892d00fbSIan Rogers 	char				*event_buf;
5197406a7eSAdrian Hunter };
5297406a7eSAdrian Hunter 
5397406a7eSAdrian Hunter struct guest_id {
5497406a7eSAdrian Hunter 	/* hlist_node must be first, see free_hlist() */
5597406a7eSAdrian Hunter 	struct hlist_node		node;
5697406a7eSAdrian Hunter 	u64				id;
5797406a7eSAdrian Hunter 	u64				host_id;
5897406a7eSAdrian Hunter 	u32				vcpu;
5997406a7eSAdrian Hunter };
6097406a7eSAdrian Hunter 
6197406a7eSAdrian Hunter struct guest_tid {
6297406a7eSAdrian Hunter 	/* hlist_node must be first, see free_hlist() */
6397406a7eSAdrian Hunter 	struct hlist_node		node;
6497406a7eSAdrian Hunter 	/* Thread ID of QEMU thread */
6597406a7eSAdrian Hunter 	u32				tid;
6697406a7eSAdrian Hunter 	u32				vcpu;
6797406a7eSAdrian Hunter };
6897406a7eSAdrian Hunter 
6997406a7eSAdrian Hunter struct guest_vcpu {
7097406a7eSAdrian Hunter 	/* Current host CPU */
7197406a7eSAdrian Hunter 	u32				cpu;
7297406a7eSAdrian Hunter 	/* Thread ID of QEMU thread */
7397406a7eSAdrian Hunter 	u32				tid;
7497406a7eSAdrian Hunter };
7597406a7eSAdrian Hunter 
7697406a7eSAdrian Hunter struct guest_session {
7797406a7eSAdrian Hunter 	char				*perf_data_file;
7897406a7eSAdrian Hunter 	u32				machine_pid;
7997406a7eSAdrian Hunter 	u64				time_offset;
8097406a7eSAdrian Hunter 	double				time_scale;
8197406a7eSAdrian Hunter 	struct perf_tool		tool;
8297406a7eSAdrian Hunter 	struct perf_data		data;
8397406a7eSAdrian Hunter 	struct perf_session		*session;
8497406a7eSAdrian Hunter 	char				*tmp_file_name;
8597406a7eSAdrian Hunter 	int				tmp_fd;
8697406a7eSAdrian Hunter 	struct perf_tsc_conversion	host_tc;
8797406a7eSAdrian Hunter 	struct perf_tsc_conversion	guest_tc;
8897406a7eSAdrian Hunter 	bool				copy_kcore_dir;
8997406a7eSAdrian Hunter 	bool				have_tc;
9097406a7eSAdrian Hunter 	bool				fetched;
9197406a7eSAdrian Hunter 	bool				ready;
9297406a7eSAdrian Hunter 	u16				dflt_id_hdr_size;
9397406a7eSAdrian Hunter 	u64				dflt_id;
9497406a7eSAdrian Hunter 	u64				highest_id;
9597406a7eSAdrian Hunter 	/* Array of guest_vcpu */
9697406a7eSAdrian Hunter 	struct guest_vcpu		*vcpu;
9797406a7eSAdrian Hunter 	size_t				vcpu_cnt;
9897406a7eSAdrian Hunter 	/* Hash table for guest_id */
9997406a7eSAdrian Hunter 	struct hlist_head		heads[PERF_EVLIST__HLIST_SIZE];
10097406a7eSAdrian Hunter 	/* Hash table for guest_tid */
10197406a7eSAdrian Hunter 	struct hlist_head		tids[PERF_EVLIST__HLIST_SIZE];
10297406a7eSAdrian Hunter 	/* Place to stash next guest event */
10397406a7eSAdrian Hunter 	struct guest_event		ev;
10497406a7eSAdrian Hunter };
10526a031e1SAndrew Vagin 
1065ded57acSArnaldo Carvalho de Melo struct perf_inject {
1075ded57acSArnaldo Carvalho de Melo 	struct perf_tool	tool;
1081cb8bdccSNamhyung Kim 	struct perf_session	*session;
1095ded57acSArnaldo Carvalho de Melo 	bool			build_ids;
11027c9c342SNamhyung Kim 	bool			build_id_all;
11126a031e1SAndrew Vagin 	bool			sched_stat;
112cd10b289SAdrian Hunter 	bool			have_auxtrace;
113f56fb986SAdrian Hunter 	bool			strip;
1149b07e27fSStephane Eranian 	bool			jit_mode;
1152a525f6aSAdrian Hunter 	bool			in_place_update;
1162a525f6aSAdrian Hunter 	bool			in_place_update_dry_run;
117fea20d66SNamhyung Kim 	bool			is_pipe;
118d8fc0855SAdrian Hunter 	bool			copy_kcore_dir;
119e558a5bdSAndrew Vagin 	const char		*input_name;
1208ceb41d7SJiri Olsa 	struct perf_data	output;
121e558a5bdSAndrew Vagin 	u64			bytes_written;
12273117308SAdrian Hunter 	u64			aux_id;
12326a031e1SAndrew Vagin 	struct list_head	samples;
1240f0aa5e0SAdrian Hunter 	struct itrace_synth_opts itrace_synth_opts;
125d3944f0eSIan Rogers 	char			*event_copy;
126180b3d06SAdrian Hunter 	struct perf_file_section secs[HEADER_FEAT_BITS];
12797406a7eSAdrian Hunter 	struct guest_session	guest_session;
1288012243eSRaul Silvera 	struct strlist		*known_build_ids;
12926a031e1SAndrew Vagin };
13026a031e1SAndrew Vagin 
13126a031e1SAndrew Vagin struct event_entry {
13226a031e1SAndrew Vagin 	struct list_head node;
13326a031e1SAndrew Vagin 	u32		 tid;
1346549a8c0SGustavo A. R. Silva 	union perf_event event[];
1355ded57acSArnaldo Carvalho de Melo };
136454c407eSTom Zanussi 
13727c9c342SNamhyung Kim static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
13827c9c342SNamhyung Kim 				struct machine *machine, u8 cpumode, u32 flags);
13927c9c342SNamhyung Kim 
output_bytes(struct perf_inject * inject,void * buf,size_t sz)140cd17a9b5SAdrian Hunter static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
141454c407eSTom Zanussi {
1423406912cSJiri Olsa 	ssize_t size;
143454c407eSTom Zanussi 
1448ceb41d7SJiri Olsa 	size = perf_data__write(&inject->output, buf, sz);
1453406912cSJiri Olsa 	if (size < 0)
146454c407eSTom Zanussi 		return -errno;
147454c407eSTom Zanussi 
1483406912cSJiri Olsa 	inject->bytes_written += size;
149454c407eSTom Zanussi 	return 0;
150454c407eSTom Zanussi }
151454c407eSTom Zanussi 
perf_event__repipe_synth(struct perf_tool * tool,union perf_event * event)152cd17a9b5SAdrian Hunter static int perf_event__repipe_synth(struct perf_tool *tool,
153cd17a9b5SAdrian Hunter 				    union perf_event *event)
154cd17a9b5SAdrian Hunter {
155cd17a9b5SAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject,
156cd17a9b5SAdrian Hunter 						  tool);
157cd17a9b5SAdrian Hunter 
158cd17a9b5SAdrian Hunter 	return output_bytes(inject, event, event->header.size);
159cd17a9b5SAdrian Hunter }
160cd17a9b5SAdrian Hunter 
perf_event__repipe_oe_synth(struct perf_tool * tool,union perf_event * event,struct ordered_events * oe __maybe_unused)161d704ebdaSArnaldo Carvalho de Melo static int perf_event__repipe_oe_synth(struct perf_tool *tool,
162d704ebdaSArnaldo Carvalho de Melo 				       union perf_event *event,
163d704ebdaSArnaldo Carvalho de Melo 				       struct ordered_events *oe __maybe_unused)
164d704ebdaSArnaldo Carvalho de Melo {
165d704ebdaSArnaldo Carvalho de Melo 	return perf_event__repipe_synth(tool, event);
166d704ebdaSArnaldo Carvalho de Melo }
167d704ebdaSArnaldo Carvalho de Melo 
168e12b202fSJiri Olsa #ifdef HAVE_JITDUMP
perf_event__drop_oe(struct perf_tool * tool __maybe_unused,union perf_event * event __maybe_unused,struct ordered_events * oe __maybe_unused)1699b07e27fSStephane Eranian static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
1709b07e27fSStephane Eranian 			       union perf_event *event __maybe_unused,
1719b07e27fSStephane Eranian 			       struct ordered_events *oe __maybe_unused)
1729b07e27fSStephane Eranian {
1739b07e27fSStephane Eranian 	return 0;
1749b07e27fSStephane Eranian }
1759b07e27fSStephane Eranian #endif
1769b07e27fSStephane Eranian 
perf_event__repipe_op2_synth(struct perf_session * session,union perf_event * event)17789f1688aSJiri Olsa static int perf_event__repipe_op2_synth(struct perf_session *session,
17889f1688aSJiri Olsa 					union perf_event *event)
179d20deb64SArnaldo Carvalho de Melo {
18089f1688aSJiri Olsa 	return perf_event__repipe_synth(session->tool, event);
181743eb868SArnaldo Carvalho de Melo }
182743eb868SArnaldo Carvalho de Melo 
perf_event__repipe_op4_synth(struct perf_session * session,union perf_event * event,u64 data __maybe_unused,const char * str __maybe_unused)1832946ecedSNamhyung Kim static int perf_event__repipe_op4_synth(struct perf_session *session,
1842946ecedSNamhyung Kim 					union perf_event *event,
1852292083fSAlexey Bayduraev 					u64 data __maybe_unused,
1862292083fSAlexey Bayduraev 					const char *str __maybe_unused)
1872946ecedSNamhyung Kim {
1882946ecedSNamhyung Kim 	return perf_event__repipe_synth(session->tool, event);
1892946ecedSNamhyung Kim }
1902946ecedSNamhyung Kim 
perf_event__repipe_attr(struct perf_tool * tool,union perf_event * event,struct evlist ** pevlist)19147c3d109SAdrian Hunter static int perf_event__repipe_attr(struct perf_tool *tool,
19247c3d109SAdrian Hunter 				   union perf_event *event,
19363503dbaSJiri Olsa 				   struct evlist **pevlist)
19410d0f086SArnaldo Carvalho de Melo {
19589c97d93SAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject,
19689c97d93SAdrian Hunter 						  tool);
1971a1ed1baSStephane Eranian 	int ret;
19847c3d109SAdrian Hunter 
19947c3d109SAdrian Hunter 	ret = perf_event__process_attr(tool, event, pevlist);
2001a1ed1baSStephane Eranian 	if (ret)
2011a1ed1baSStephane Eranian 		return ret;
2021a1ed1baSStephane Eranian 
203fea20d66SNamhyung Kim 	if (!inject->is_pipe)
20489c97d93SAdrian Hunter 		return 0;
20589c97d93SAdrian Hunter 
20647c3d109SAdrian Hunter 	return perf_event__repipe_synth(tool, event);
20710d0f086SArnaldo Carvalho de Melo }
20810d0f086SArnaldo Carvalho de Melo 
perf_event__repipe_event_update(struct perf_tool * tool,union perf_event * event,struct evlist ** pevlist __maybe_unused)2092946ecedSNamhyung Kim static int perf_event__repipe_event_update(struct perf_tool *tool,
2102946ecedSNamhyung Kim 					   union perf_event *event,
2112946ecedSNamhyung Kim 					   struct evlist **pevlist __maybe_unused)
2122946ecedSNamhyung Kim {
2132946ecedSNamhyung Kim 	return perf_event__repipe_synth(tool, event);
2142946ecedSNamhyung Kim }
2152946ecedSNamhyung Kim 
216e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
217e31f0d01SAdrian Hunter 
copy_bytes(struct perf_inject * inject,struct perf_data * data,off_t size)2181746212dSNamhyung Kim static int copy_bytes(struct perf_inject *inject, struct perf_data *data, off_t size)
219e31f0d01SAdrian Hunter {
220e31f0d01SAdrian Hunter 	char buf[4096];
221e31f0d01SAdrian Hunter 	ssize_t ssz;
222e31f0d01SAdrian Hunter 	int ret;
223e31f0d01SAdrian Hunter 
224e31f0d01SAdrian Hunter 	while (size > 0) {
2251746212dSNamhyung Kim 		ssz = perf_data__read(data, buf, min(size, (off_t)sizeof(buf)));
226e31f0d01SAdrian Hunter 		if (ssz < 0)
227e31f0d01SAdrian Hunter 			return -errno;
228e31f0d01SAdrian Hunter 		ret = output_bytes(inject, buf, ssz);
229e31f0d01SAdrian Hunter 		if (ret)
230e31f0d01SAdrian Hunter 			return ret;
231e31f0d01SAdrian Hunter 		size -= ssz;
232e31f0d01SAdrian Hunter 	}
233e31f0d01SAdrian Hunter 
234e31f0d01SAdrian Hunter 	return 0;
235e31f0d01SAdrian Hunter }
236e31f0d01SAdrian Hunter 
perf_event__repipe_auxtrace(struct perf_session * session,union perf_event * event)2377336555aSJiri Olsa static s64 perf_event__repipe_auxtrace(struct perf_session *session,
2387336555aSJiri Olsa 				       union perf_event *event)
239cd17a9b5SAdrian Hunter {
2407336555aSJiri Olsa 	struct perf_tool *tool = session->tool;
241cd17a9b5SAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject,
242cd17a9b5SAdrian Hunter 						  tool);
243cd17a9b5SAdrian Hunter 	int ret;
244cd17a9b5SAdrian Hunter 
245cd10b289SAdrian Hunter 	inject->have_auxtrace = true;
246cd10b289SAdrian Hunter 
24799fa2984SAdrian Hunter 	if (!inject->output.is_pipe) {
24899fa2984SAdrian Hunter 		off_t offset;
24999fa2984SAdrian Hunter 
250eae8ad80SJiri Olsa 		offset = lseek(inject->output.file.fd, 0, SEEK_CUR);
25199fa2984SAdrian Hunter 		if (offset == -1)
25299fa2984SAdrian Hunter 			return -errno;
25399fa2984SAdrian Hunter 		ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
25499fa2984SAdrian Hunter 						     event, offset);
25599fa2984SAdrian Hunter 		if (ret < 0)
25699fa2984SAdrian Hunter 			return ret;
25799fa2984SAdrian Hunter 	}
25899fa2984SAdrian Hunter 
2598ceb41d7SJiri Olsa 	if (perf_data__is_pipe(session->data) || !session->one_mmap) {
260cd17a9b5SAdrian Hunter 		ret = output_bytes(inject, event, event->header.size);
261cd17a9b5SAdrian Hunter 		if (ret < 0)
262cd17a9b5SAdrian Hunter 			return ret;
2631746212dSNamhyung Kim 		ret = copy_bytes(inject, session->data,
264cd17a9b5SAdrian Hunter 				 event->auxtrace.size);
265cd17a9b5SAdrian Hunter 	} else {
266cd17a9b5SAdrian Hunter 		ret = output_bytes(inject, event,
267cd17a9b5SAdrian Hunter 				   event->header.size + event->auxtrace.size);
268cd17a9b5SAdrian Hunter 	}
269cd17a9b5SAdrian Hunter 	if (ret < 0)
270cd17a9b5SAdrian Hunter 		return ret;
271cd17a9b5SAdrian Hunter 
272cd17a9b5SAdrian Hunter 	return event->auxtrace.size;
273cd17a9b5SAdrian Hunter }
274cd17a9b5SAdrian Hunter 
275e31f0d01SAdrian Hunter #else
276e31f0d01SAdrian Hunter 
277e31f0d01SAdrian Hunter static s64
perf_event__repipe_auxtrace(struct perf_session * session __maybe_unused,union perf_event * event __maybe_unused)2787336555aSJiri Olsa perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused,
2797336555aSJiri Olsa 			    union perf_event *event __maybe_unused)
280e31f0d01SAdrian Hunter {
281e31f0d01SAdrian Hunter 	pr_err("AUX area tracing not supported\n");
282e31f0d01SAdrian Hunter 	return -EINVAL;
283e31f0d01SAdrian Hunter }
284e31f0d01SAdrian Hunter 
285e31f0d01SAdrian Hunter #endif
286e31f0d01SAdrian Hunter 
perf_event__repipe(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)28745694aa7SArnaldo Carvalho de Melo static int perf_event__repipe(struct perf_tool *tool,
288d20deb64SArnaldo Carvalho de Melo 			      union perf_event *event,
2891d037ca1SIrina Tirdea 			      struct perf_sample *sample __maybe_unused,
29063c2c9f8SAdrian Hunter 			      struct machine *machine __maybe_unused)
291640c03ceSArnaldo Carvalho de Melo {
29263c2c9f8SAdrian Hunter 	return perf_event__repipe_synth(tool, event);
293640c03ceSArnaldo Carvalho de Melo }
294640c03ceSArnaldo Carvalho de Melo 
perf_event__drop(struct perf_tool * tool __maybe_unused,union perf_event * event __maybe_unused,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)295f56fb986SAdrian Hunter static int perf_event__drop(struct perf_tool *tool __maybe_unused,
296f56fb986SAdrian Hunter 			    union perf_event *event __maybe_unused,
297f56fb986SAdrian Hunter 			    struct perf_sample *sample __maybe_unused,
298f56fb986SAdrian Hunter 			    struct machine *machine __maybe_unused)
299f56fb986SAdrian Hunter {
300f56fb986SAdrian Hunter 	return 0;
301f56fb986SAdrian Hunter }
302f56fb986SAdrian Hunter 
perf_event__drop_aux(struct perf_tool * tool,union perf_event * event __maybe_unused,struct perf_sample * sample,struct machine * machine __maybe_unused)30373117308SAdrian Hunter static int perf_event__drop_aux(struct perf_tool *tool,
30473117308SAdrian Hunter 				union perf_event *event __maybe_unused,
30573117308SAdrian Hunter 				struct perf_sample *sample,
30673117308SAdrian Hunter 				struct machine *machine __maybe_unused)
30773117308SAdrian Hunter {
30873117308SAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
30973117308SAdrian Hunter 
31073117308SAdrian Hunter 	if (!inject->aux_id)
31173117308SAdrian Hunter 		inject->aux_id = sample->id;
31273117308SAdrian Hunter 
31373117308SAdrian Hunter 	return 0;
31473117308SAdrian Hunter }
31573117308SAdrian Hunter 
316ba2675bfSAdrian Hunter static union perf_event *
perf_inject__cut_auxtrace_sample(struct perf_inject * inject,union perf_event * event,struct perf_sample * sample)317ba2675bfSAdrian Hunter perf_inject__cut_auxtrace_sample(struct perf_inject *inject,
318ba2675bfSAdrian Hunter 				 union perf_event *event,
319ba2675bfSAdrian Hunter 				 struct perf_sample *sample)
320ba2675bfSAdrian Hunter {
321ba2675bfSAdrian Hunter 	size_t sz1 = sample->aux_sample.data - (void *)event;
322ba2675bfSAdrian Hunter 	size_t sz2 = event->header.size - sample->aux_sample.size - sz1;
323d3944f0eSIan Rogers 	union perf_event *ev;
324ba2675bfSAdrian Hunter 
325d3944f0eSIan Rogers 	if (inject->event_copy == NULL) {
326d3944f0eSIan Rogers 		inject->event_copy = malloc(PERF_SAMPLE_MAX_SIZE);
327d3944f0eSIan Rogers 		if (!inject->event_copy)
328d3944f0eSIan Rogers 			return ERR_PTR(-ENOMEM);
329d3944f0eSIan Rogers 	}
330d3944f0eSIan Rogers 	ev = (union perf_event *)inject->event_copy;
331ba2675bfSAdrian Hunter 	if (sz1 > event->header.size || sz2 > event->header.size ||
332ba2675bfSAdrian Hunter 	    sz1 + sz2 > event->header.size ||
333ba2675bfSAdrian Hunter 	    sz1 < sizeof(struct perf_event_header) + sizeof(u64))
334ba2675bfSAdrian Hunter 		return event;
335ba2675bfSAdrian Hunter 
336ba2675bfSAdrian Hunter 	memcpy(ev, event, sz1);
337ba2675bfSAdrian Hunter 	memcpy((void *)ev + sz1, (void *)event + event->header.size - sz2, sz2);
338ba2675bfSAdrian Hunter 	ev->header.size = sz1 + sz2;
339ba2675bfSAdrian Hunter 	((u64 *)((void *)ev + sz1))[-1] = 0;
340ba2675bfSAdrian Hunter 
341ba2675bfSAdrian Hunter 	return ev;
342ba2675bfSAdrian Hunter }
343ba2675bfSAdrian Hunter 
34426a031e1SAndrew Vagin typedef int (*inject_handler)(struct perf_tool *tool,
34526a031e1SAndrew Vagin 			      union perf_event *event,
34626a031e1SAndrew Vagin 			      struct perf_sample *sample,
34732dcd021SJiri Olsa 			      struct evsel *evsel,
34826a031e1SAndrew Vagin 			      struct machine *machine);
34926a031e1SAndrew Vagin 
perf_event__repipe_sample(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct evsel * evsel,struct machine * machine)35045694aa7SArnaldo Carvalho de Melo static int perf_event__repipe_sample(struct perf_tool *tool,
351d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
35226a031e1SAndrew Vagin 				     struct perf_sample *sample,
35332dcd021SJiri Olsa 				     struct evsel *evsel,
354743eb868SArnaldo Carvalho de Melo 				     struct machine *machine)
3559e69c210SArnaldo Carvalho de Melo {
356ba2675bfSAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject,
357ba2675bfSAdrian Hunter 						  tool);
358ba2675bfSAdrian Hunter 
35940978e9bSArnaldo Carvalho de Melo 	if (evsel && evsel->handler) {
360744a9719SArnaldo Carvalho de Melo 		inject_handler f = evsel->handler;
36126a031e1SAndrew Vagin 		return f(tool, event, sample, evsel, machine);
36226a031e1SAndrew Vagin 	}
36326a031e1SAndrew Vagin 
36454a3cf59SAndrew Vagin 	build_id__mark_dso_hit(tool, event, sample, evsel, machine);
36554a3cf59SAndrew Vagin 
366d3944f0eSIan Rogers 	if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
367ba2675bfSAdrian Hunter 		event = perf_inject__cut_auxtrace_sample(inject, event, sample);
368d3944f0eSIan Rogers 		if (IS_ERR(event))
369d3944f0eSIan Rogers 			return PTR_ERR(event);
370d3944f0eSIan Rogers 	}
371ba2675bfSAdrian Hunter 
37263c2c9f8SAdrian Hunter 	return perf_event__repipe_synth(tool, event);
3739e69c210SArnaldo Carvalho de Melo }
3749e69c210SArnaldo Carvalho de Melo 
perf_event__repipe_mmap(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)37545694aa7SArnaldo Carvalho de Melo static int perf_event__repipe_mmap(struct perf_tool *tool,
376d20deb64SArnaldo Carvalho de Melo 				   union perf_event *event,
3778115d60cSArnaldo Carvalho de Melo 				   struct perf_sample *sample,
378743eb868SArnaldo Carvalho de Melo 				   struct machine *machine)
379454c407eSTom Zanussi {
380454c407eSTom Zanussi 	int err;
381454c407eSTom Zanussi 
38245694aa7SArnaldo Carvalho de Melo 	err = perf_event__process_mmap(tool, event, sample, machine);
38345694aa7SArnaldo Carvalho de Melo 	perf_event__repipe(tool, event, sample, machine);
384454c407eSTom Zanussi 
385454c407eSTom Zanussi 	return err;
386454c407eSTom Zanussi }
387454c407eSTom Zanussi 
388e12b202fSJiri Olsa #ifdef HAVE_JITDUMP
perf_event__jit_repipe_mmap(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)3899b07e27fSStephane Eranian static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
3909b07e27fSStephane Eranian 				       union perf_event *event,
3919b07e27fSStephane Eranian 				       struct perf_sample *sample,
3929b07e27fSStephane Eranian 				       struct machine *machine)
3939b07e27fSStephane Eranian {
3949b07e27fSStephane Eranian 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
3959b07e27fSStephane Eranian 	u64 n = 0;
396570735b3SAdrian Hunter 	int ret;
3979b07e27fSStephane Eranian 
3989b07e27fSStephane Eranian 	/*
3999b07e27fSStephane Eranian 	 * if jit marker, then inject jit mmaps and generate ELF images
4009b07e27fSStephane Eranian 	 */
401570735b3SAdrian Hunter 	ret = jit_process(inject->session, &inject->output, machine,
40267dec926SYonatan Goldschmidt 			  event->mmap.filename, event->mmap.pid, event->mmap.tid, &n);
403570735b3SAdrian Hunter 	if (ret < 0)
404570735b3SAdrian Hunter 		return ret;
405570735b3SAdrian Hunter 	if (ret) {
4069b07e27fSStephane Eranian 		inject->bytes_written += n;
4079b07e27fSStephane Eranian 		return 0;
4089b07e27fSStephane Eranian 	}
4099b07e27fSStephane Eranian 	return perf_event__repipe_mmap(tool, event, sample, machine);
4109b07e27fSStephane Eranian }
4119b07e27fSStephane Eranian #endif
4129b07e27fSStephane Eranian 
findnew_dso(int pid,int tid,const char * filename,struct dso_id * id,struct machine * machine)41327c9c342SNamhyung Kim static struct dso *findnew_dso(int pid, int tid, const char *filename,
41427c9c342SNamhyung Kim 			       struct dso_id *id, struct machine *machine)
41527c9c342SNamhyung Kim {
41627c9c342SNamhyung Kim 	struct thread *thread;
41727c9c342SNamhyung Kim 	struct nsinfo *nsi = NULL;
41827c9c342SNamhyung Kim 	struct nsinfo *nnsi;
41927c9c342SNamhyung Kim 	struct dso *dso;
42027c9c342SNamhyung Kim 	bool vdso;
42127c9c342SNamhyung Kim 
42227c9c342SNamhyung Kim 	thread = machine__findnew_thread(machine, pid, tid);
42327c9c342SNamhyung Kim 	if (thread == NULL) {
42427c9c342SNamhyung Kim 		pr_err("cannot find or create a task %d/%d.\n", tid, pid);
42527c9c342SNamhyung Kim 		return NULL;
42627c9c342SNamhyung Kim 	}
42727c9c342SNamhyung Kim 
42827c9c342SNamhyung Kim 	vdso = is_vdso_map(filename);
429ee84a303SIan Rogers 	nsi = nsinfo__get(thread__nsinfo(thread));
43027c9c342SNamhyung Kim 
43127c9c342SNamhyung Kim 	if (vdso) {
43227c9c342SNamhyung Kim 		/* The vdso maps are always on the host and not the
43327c9c342SNamhyung Kim 		 * container.  Ensure that we don't use setns to look
43427c9c342SNamhyung Kim 		 * them up.
43527c9c342SNamhyung Kim 		 */
43627c9c342SNamhyung Kim 		nnsi = nsinfo__copy(nsi);
43727c9c342SNamhyung Kim 		if (nnsi) {
43827c9c342SNamhyung Kim 			nsinfo__put(nsi);
439bcaf0a97SIan Rogers 			nsinfo__clear_need_setns(nnsi);
44027c9c342SNamhyung Kim 			nsi = nnsi;
44127c9c342SNamhyung Kim 		}
44227c9c342SNamhyung Kim 		dso = machine__findnew_vdso(machine, thread);
44327c9c342SNamhyung Kim 	} else {
44427c9c342SNamhyung Kim 		dso = machine__findnew_dso_id(machine, filename, id);
44527c9c342SNamhyung Kim 	}
44627c9c342SNamhyung Kim 
4470967ebffSRiccardo Mancini 	if (dso) {
448e54dea69SIan Rogers 		mutex_lock(&dso->lock);
4490967ebffSRiccardo Mancini 		nsinfo__put(dso->nsinfo);
45027c9c342SNamhyung Kim 		dso->nsinfo = nsi;
451e54dea69SIan Rogers 		mutex_unlock(&dso->lock);
4520967ebffSRiccardo Mancini 	} else
45327c9c342SNamhyung Kim 		nsinfo__put(nsi);
45427c9c342SNamhyung Kim 
45527c9c342SNamhyung Kim 	thread__put(thread);
45627c9c342SNamhyung Kim 	return dso;
45727c9c342SNamhyung Kim }
45827c9c342SNamhyung Kim 
perf_event__repipe_buildid_mmap(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)45927c9c342SNamhyung Kim static int perf_event__repipe_buildid_mmap(struct perf_tool *tool,
46027c9c342SNamhyung Kim 					   union perf_event *event,
46127c9c342SNamhyung Kim 					   struct perf_sample *sample,
46227c9c342SNamhyung Kim 					   struct machine *machine)
46327c9c342SNamhyung Kim {
46427c9c342SNamhyung Kim 	struct dso *dso;
46527c9c342SNamhyung Kim 
46627c9c342SNamhyung Kim 	dso = findnew_dso(event->mmap.pid, event->mmap.tid,
46727c9c342SNamhyung Kim 			  event->mmap.filename, NULL, machine);
46827c9c342SNamhyung Kim 
46927c9c342SNamhyung Kim 	if (dso && !dso->hit) {
47027c9c342SNamhyung Kim 		dso->hit = 1;
47127c9c342SNamhyung Kim 		dso__inject_build_id(dso, tool, machine, sample->cpumode, 0);
47227c9c342SNamhyung Kim 	}
4730c3f7b38SNamhyung Kim 	dso__put(dso);
47427c9c342SNamhyung Kim 
47527c9c342SNamhyung Kim 	return perf_event__repipe(tool, event, sample, machine);
47627c9c342SNamhyung Kim }
47727c9c342SNamhyung Kim 
perf_event__repipe_mmap2(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)4785c5e854bSStephane Eranian static int perf_event__repipe_mmap2(struct perf_tool *tool,
4795c5e854bSStephane Eranian 				   union perf_event *event,
4805c5e854bSStephane Eranian 				   struct perf_sample *sample,
4815c5e854bSStephane Eranian 				   struct machine *machine)
4825c5e854bSStephane Eranian {
4835c5e854bSStephane Eranian 	int err;
4845c5e854bSStephane Eranian 
4855c5e854bSStephane Eranian 	err = perf_event__process_mmap2(tool, event, sample, machine);
4865c5e854bSStephane Eranian 	perf_event__repipe(tool, event, sample, machine);
4875c5e854bSStephane Eranian 
488f7fc0d1cSNamhyung Kim 	if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
489f7fc0d1cSNamhyung Kim 		struct dso *dso;
490f7fc0d1cSNamhyung Kim 
491f7fc0d1cSNamhyung Kim 		dso = findnew_dso(event->mmap2.pid, event->mmap2.tid,
492f7fc0d1cSNamhyung Kim 				  event->mmap2.filename, NULL, machine);
493f7fc0d1cSNamhyung Kim 		if (dso) {
494f7fc0d1cSNamhyung Kim 			/* mark it not to inject build-id */
495f7fc0d1cSNamhyung Kim 			dso->hit = 1;
496f7fc0d1cSNamhyung Kim 		}
497f7fc0d1cSNamhyung Kim 		dso__put(dso);
498f7fc0d1cSNamhyung Kim 	}
499f7fc0d1cSNamhyung Kim 
5005c5e854bSStephane Eranian 	return err;
5015c5e854bSStephane Eranian }
5025c5e854bSStephane Eranian 
503e12b202fSJiri Olsa #ifdef HAVE_JITDUMP
perf_event__jit_repipe_mmap2(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)5049b07e27fSStephane Eranian static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
5059b07e27fSStephane Eranian 					union perf_event *event,
5069b07e27fSStephane Eranian 					struct perf_sample *sample,
5079b07e27fSStephane Eranian 					struct machine *machine)
5089b07e27fSStephane Eranian {
5099b07e27fSStephane Eranian 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
5109b07e27fSStephane Eranian 	u64 n = 0;
511570735b3SAdrian Hunter 	int ret;
5129b07e27fSStephane Eranian 
5139b07e27fSStephane Eranian 	/*
5149b07e27fSStephane Eranian 	 * if jit marker, then inject jit mmaps and generate ELF images
5159b07e27fSStephane Eranian 	 */
516570735b3SAdrian Hunter 	ret = jit_process(inject->session, &inject->output, machine,
51767dec926SYonatan Goldschmidt 			  event->mmap2.filename, event->mmap2.pid, event->mmap2.tid, &n);
518570735b3SAdrian Hunter 	if (ret < 0)
519570735b3SAdrian Hunter 		return ret;
520570735b3SAdrian Hunter 	if (ret) {
5219b07e27fSStephane Eranian 		inject->bytes_written += n;
5229b07e27fSStephane Eranian 		return 0;
5239b07e27fSStephane Eranian 	}
5249b07e27fSStephane Eranian 	return perf_event__repipe_mmap2(tool, event, sample, machine);
5259b07e27fSStephane Eranian }
5269b07e27fSStephane Eranian #endif
5279b07e27fSStephane Eranian 
perf_event__repipe_buildid_mmap2(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)52827c9c342SNamhyung Kim static int perf_event__repipe_buildid_mmap2(struct perf_tool *tool,
52927c9c342SNamhyung Kim 					    union perf_event *event,
53027c9c342SNamhyung Kim 					    struct perf_sample *sample,
53127c9c342SNamhyung Kim 					    struct machine *machine)
53227c9c342SNamhyung Kim {
53327c9c342SNamhyung Kim 	struct dso_id dso_id = {
53427c9c342SNamhyung Kim 		.maj = event->mmap2.maj,
53527c9c342SNamhyung Kim 		.min = event->mmap2.min,
53627c9c342SNamhyung Kim 		.ino = event->mmap2.ino,
53727c9c342SNamhyung Kim 		.ino_generation = event->mmap2.ino_generation,
53827c9c342SNamhyung Kim 	};
53927c9c342SNamhyung Kim 	struct dso *dso;
54027c9c342SNamhyung Kim 
541f7fc0d1cSNamhyung Kim 	if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
542f7fc0d1cSNamhyung Kim 		/* cannot use dso_id since it'd have invalid info */
543f7fc0d1cSNamhyung Kim 		dso = findnew_dso(event->mmap2.pid, event->mmap2.tid,
544f7fc0d1cSNamhyung Kim 				  event->mmap2.filename, NULL, machine);
545f7fc0d1cSNamhyung Kim 		if (dso) {
546f7fc0d1cSNamhyung Kim 			/* mark it not to inject build-id */
547f7fc0d1cSNamhyung Kim 			dso->hit = 1;
548f7fc0d1cSNamhyung Kim 		}
549f7fc0d1cSNamhyung Kim 		dso__put(dso);
550ce9f1c05SNamhyung Kim 		perf_event__repipe(tool, event, sample, machine);
551f7fc0d1cSNamhyung Kim 		return 0;
552f7fc0d1cSNamhyung Kim 	}
553f7fc0d1cSNamhyung Kim 
55427c9c342SNamhyung Kim 	dso = findnew_dso(event->mmap2.pid, event->mmap2.tid,
55527c9c342SNamhyung Kim 			  event->mmap2.filename, &dso_id, machine);
55627c9c342SNamhyung Kim 
55727c9c342SNamhyung Kim 	if (dso && !dso->hit) {
55827c9c342SNamhyung Kim 		dso->hit = 1;
55927c9c342SNamhyung Kim 		dso__inject_build_id(dso, tool, machine, sample->cpumode,
56027c9c342SNamhyung Kim 				     event->mmap2.flags);
56127c9c342SNamhyung Kim 	}
5620c3f7b38SNamhyung Kim 	dso__put(dso);
56327c9c342SNamhyung Kim 
56427c9c342SNamhyung Kim 	perf_event__repipe(tool, event, sample, machine);
56527c9c342SNamhyung Kim 
56627c9c342SNamhyung Kim 	return 0;
56727c9c342SNamhyung Kim }
56827c9c342SNamhyung Kim 
perf_event__repipe_fork(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)569f62d3f0fSArnaldo Carvalho de Melo static int perf_event__repipe_fork(struct perf_tool *tool,
570d20deb64SArnaldo Carvalho de Melo 				   union perf_event *event,
5718115d60cSArnaldo Carvalho de Melo 				   struct perf_sample *sample,
572743eb868SArnaldo Carvalho de Melo 				   struct machine *machine)
573454c407eSTom Zanussi {
574454c407eSTom Zanussi 	int err;
575454c407eSTom Zanussi 
576f62d3f0fSArnaldo Carvalho de Melo 	err = perf_event__process_fork(tool, event, sample, machine);
57745694aa7SArnaldo Carvalho de Melo 	perf_event__repipe(tool, event, sample, machine);
578454c407eSTom Zanussi 
579454c407eSTom Zanussi 	return err;
580454c407eSTom Zanussi }
581454c407eSTom Zanussi 
perf_event__repipe_comm(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)5820f0aa5e0SAdrian Hunter static int perf_event__repipe_comm(struct perf_tool *tool,
5830f0aa5e0SAdrian Hunter 				   union perf_event *event,
5840f0aa5e0SAdrian Hunter 				   struct perf_sample *sample,
5850f0aa5e0SAdrian Hunter 				   struct machine *machine)
5860f0aa5e0SAdrian Hunter {
5870f0aa5e0SAdrian Hunter 	int err;
5880f0aa5e0SAdrian Hunter 
5890f0aa5e0SAdrian Hunter 	err = perf_event__process_comm(tool, event, sample, machine);
5900f0aa5e0SAdrian Hunter 	perf_event__repipe(tool, event, sample, machine);
5910f0aa5e0SAdrian Hunter 
5920f0aa5e0SAdrian Hunter 	return err;
5930f0aa5e0SAdrian Hunter }
5940f0aa5e0SAdrian Hunter 
perf_event__repipe_namespaces(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)595f3b3614aSHari Bathini static int perf_event__repipe_namespaces(struct perf_tool *tool,
596f3b3614aSHari Bathini 					 union perf_event *event,
597f3b3614aSHari Bathini 					 struct perf_sample *sample,
598f3b3614aSHari Bathini 					 struct machine *machine)
599f3b3614aSHari Bathini {
600f3b3614aSHari Bathini 	int err = perf_event__process_namespaces(tool, event, sample, machine);
601f3b3614aSHari Bathini 
602f3b3614aSHari Bathini 	perf_event__repipe(tool, event, sample, machine);
603f3b3614aSHari Bathini 
604f3b3614aSHari Bathini 	return err;
605f3b3614aSHari Bathini }
606f3b3614aSHari Bathini 
perf_event__repipe_exit(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)6070f0aa5e0SAdrian Hunter static int perf_event__repipe_exit(struct perf_tool *tool,
6080f0aa5e0SAdrian Hunter 				   union perf_event *event,
6090f0aa5e0SAdrian Hunter 				   struct perf_sample *sample,
6100f0aa5e0SAdrian Hunter 				   struct machine *machine)
6110f0aa5e0SAdrian Hunter {
6120f0aa5e0SAdrian Hunter 	int err;
6130f0aa5e0SAdrian Hunter 
6140f0aa5e0SAdrian Hunter 	err = perf_event__process_exit(tool, event, sample, machine);
6150f0aa5e0SAdrian Hunter 	perf_event__repipe(tool, event, sample, machine);
6160f0aa5e0SAdrian Hunter 
6170f0aa5e0SAdrian Hunter 	return err;
6180f0aa5e0SAdrian Hunter }
6190f0aa5e0SAdrian Hunter 
620378ef0f5SIan Rogers #ifdef HAVE_LIBTRACEEVENT
perf_event__repipe_tracing_data(struct perf_session * session,union perf_event * event)62189f1688aSJiri Olsa static int perf_event__repipe_tracing_data(struct perf_session *session,
62289f1688aSJiri Olsa 					   union perf_event *event)
623454c407eSTom Zanussi {
62489f1688aSJiri Olsa 	perf_event__repipe_synth(session->tool, event);
625454c407eSTom Zanussi 
626f0ac5b85SMinghao Chi 	return perf_event__process_tracing_data(session, event);
627454c407eSTom Zanussi }
628378ef0f5SIan Rogers #endif
629454c407eSTom Zanussi 
dso__read_build_id(struct dso * dso)630c824c433SArnaldo Carvalho de Melo static int dso__read_build_id(struct dso *dso)
631454c407eSTom Zanussi {
632336c95b2SNamhyung Kim 	struct nscookie nsc;
633336c95b2SNamhyung Kim 
634c824c433SArnaldo Carvalho de Melo 	if (dso->has_build_id)
635090f7204SArnaldo Carvalho de Melo 		return 0;
636454c407eSTom Zanussi 
637e54dea69SIan Rogers 	mutex_lock(&dso->lock);
638336c95b2SNamhyung Kim 	nsinfo__mountns_enter(dso->nsinfo, &nsc);
639f766819cSJiri Olsa 	if (filename__read_build_id(dso->long_name, &dso->bid) > 0)
640c824c433SArnaldo Carvalho de Melo 		dso->has_build_id = true;
64175d48c56SNamhyung Kim 	else if (dso->nsinfo) {
6427031edacSArnaldo Carvalho de Melo 		char *new_name = dso__filename_with_chroot(dso, dso->long_name);
64375d48c56SNamhyung Kim 
64475d48c56SNamhyung Kim 		if (new_name && filename__read_build_id(new_name, &dso->bid) > 0)
64575d48c56SNamhyung Kim 			dso->has_build_id = true;
64675d48c56SNamhyung Kim 		free(new_name);
64775d48c56SNamhyung Kim 	}
648336c95b2SNamhyung Kim 	nsinfo__mountns_exit(&nsc);
649e54dea69SIan Rogers 	mutex_unlock(&dso->lock);
650454c407eSTom Zanussi 
651336c95b2SNamhyung Kim 	return dso->has_build_id ? 0 : -1;
652090f7204SArnaldo Carvalho de Melo }
653090f7204SArnaldo Carvalho de Melo 
perf_inject__parse_known_build_ids(const char * known_build_ids_string)6548012243eSRaul Silvera static struct strlist *perf_inject__parse_known_build_ids(
6558012243eSRaul Silvera 	const char *known_build_ids_string)
6568012243eSRaul Silvera {
6578012243eSRaul Silvera 	struct str_node *pos, *tmp;
6588012243eSRaul Silvera 	struct strlist *known_build_ids;
6598012243eSRaul Silvera 	int bid_len;
6608012243eSRaul Silvera 
6618012243eSRaul Silvera 	known_build_ids = strlist__new(known_build_ids_string, NULL);
6628012243eSRaul Silvera 	if (known_build_ids == NULL)
6638012243eSRaul Silvera 		return NULL;
6648012243eSRaul Silvera 	strlist__for_each_entry_safe(pos, tmp, known_build_ids) {
6658012243eSRaul Silvera 		const char *build_id, *dso_name;
6668012243eSRaul Silvera 
6678012243eSRaul Silvera 		build_id = skip_spaces(pos->s);
6688012243eSRaul Silvera 		dso_name = strchr(build_id, ' ');
6698012243eSRaul Silvera 		if (dso_name == NULL) {
6708012243eSRaul Silvera 			strlist__remove(known_build_ids, pos);
6718012243eSRaul Silvera 			continue;
6728012243eSRaul Silvera 		}
6738012243eSRaul Silvera 		bid_len = dso_name - pos->s;
6748012243eSRaul Silvera 		dso_name = skip_spaces(dso_name);
6758012243eSRaul Silvera 		if (bid_len % 2 != 0 || bid_len >= SBUILD_ID_SIZE) {
6768012243eSRaul Silvera 			strlist__remove(known_build_ids, pos);
6778012243eSRaul Silvera 			continue;
6788012243eSRaul Silvera 		}
6798012243eSRaul Silvera 		for (int ix = 0; 2 * ix + 1 < bid_len; ++ix) {
6808012243eSRaul Silvera 			if (!isxdigit(build_id[2 * ix]) ||
6818012243eSRaul Silvera 			    !isxdigit(build_id[2 * ix + 1])) {
6828012243eSRaul Silvera 				strlist__remove(known_build_ids, pos);
6838012243eSRaul Silvera 				break;
6848012243eSRaul Silvera 			}
6858012243eSRaul Silvera 		}
6868012243eSRaul Silvera 	}
6878012243eSRaul Silvera 	return known_build_ids;
6888012243eSRaul Silvera }
6898012243eSRaul Silvera 
perf_inject__lookup_known_build_id(struct perf_inject * inject,struct dso * dso)6908012243eSRaul Silvera static bool perf_inject__lookup_known_build_id(struct perf_inject *inject,
6918012243eSRaul Silvera 					       struct dso *dso)
6928012243eSRaul Silvera {
6938012243eSRaul Silvera 	struct str_node *pos;
6948012243eSRaul Silvera 	int bid_len;
6958012243eSRaul Silvera 
6968012243eSRaul Silvera 	strlist__for_each_entry(pos, inject->known_build_ids) {
6978012243eSRaul Silvera 		const char *build_id, *dso_name;
6988012243eSRaul Silvera 
6998012243eSRaul Silvera 		build_id = skip_spaces(pos->s);
7008012243eSRaul Silvera 		dso_name = strchr(build_id, ' ');
7018012243eSRaul Silvera 		bid_len = dso_name - pos->s;
7028012243eSRaul Silvera 		dso_name = skip_spaces(dso_name);
7038012243eSRaul Silvera 		if (strcmp(dso->long_name, dso_name))
7048012243eSRaul Silvera 			continue;
7058012243eSRaul Silvera 		for (int ix = 0; 2 * ix + 1 < bid_len; ++ix) {
7068012243eSRaul Silvera 			dso->bid.data[ix] = (hex(build_id[2 * ix]) << 4 |
7078012243eSRaul Silvera 					     hex(build_id[2 * ix + 1]));
7088012243eSRaul Silvera 		}
7098012243eSRaul Silvera 		dso->bid.size = bid_len / 2;
7108012243eSRaul Silvera 		dso->has_build_id = 1;
7118012243eSRaul Silvera 		return true;
7128012243eSRaul Silvera 	}
7138012243eSRaul Silvera 	return false;
7148012243eSRaul Silvera }
7158012243eSRaul Silvera 
dso__inject_build_id(struct dso * dso,struct perf_tool * tool,struct machine * machine,u8 cpumode,u32 flags)716c824c433SArnaldo Carvalho de Melo static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
717e7b60c5aSNamhyung Kim 				struct machine *machine, u8 cpumode, u32 flags)
718090f7204SArnaldo Carvalho de Melo {
7198012243eSRaul Silvera 	struct perf_inject *inject = container_of(tool, struct perf_inject,
7208012243eSRaul Silvera 						  tool);
721090f7204SArnaldo Carvalho de Melo 	int err;
722454c407eSTom Zanussi 
723e7b60c5aSNamhyung Kim 	if (is_anon_memory(dso->long_name) || flags & MAP_HUGETLB)
724e7b60c5aSNamhyung Kim 		return 0;
725e7b60c5aSNamhyung Kim 	if (is_no_dso_memory(dso->long_name))
726e7b60c5aSNamhyung Kim 		return 0;
727e7b60c5aSNamhyung Kim 
7288012243eSRaul Silvera 	if (inject->known_build_ids != NULL &&
7298012243eSRaul Silvera 	    perf_inject__lookup_known_build_id(inject, dso))
7308012243eSRaul Silvera 		return 1;
7318012243eSRaul Silvera 
732c824c433SArnaldo Carvalho de Melo 	if (dso__read_build_id(dso) < 0) {
733c824c433SArnaldo Carvalho de Melo 		pr_debug("no build_id found for %s\n", dso->long_name);
734090f7204SArnaldo Carvalho de Melo 		return -1;
735090f7204SArnaldo Carvalho de Melo 	}
736454c407eSTom Zanussi 
737e7b60c5aSNamhyung Kim 	err = perf_event__synthesize_build_id(tool, dso, cpumode,
738e7b60c5aSNamhyung Kim 					      perf_event__repipe, machine);
739454c407eSTom Zanussi 	if (err) {
740c824c433SArnaldo Carvalho de Melo 		pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
741454c407eSTom Zanussi 		return -1;
742454c407eSTom Zanussi 	}
743454c407eSTom Zanussi 
744454c407eSTom Zanussi 	return 0;
745454c407eSTom Zanussi }
746454c407eSTom Zanussi 
perf_event__inject_buildid(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct evsel * evsel __maybe_unused,struct machine * machine)7470bf02a0dSNamhyung Kim int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event,
7488115d60cSArnaldo Carvalho de Melo 			       struct perf_sample *sample,
74932dcd021SJiri Olsa 			       struct evsel *evsel __maybe_unused,
750743eb868SArnaldo Carvalho de Melo 			       struct machine *machine)
751454c407eSTom Zanussi {
752454c407eSTom Zanussi 	struct addr_location al;
753454c407eSTom Zanussi 	struct thread *thread;
754454c407eSTom Zanussi 
7550dd5041cSIan Rogers 	addr_location__init(&al);
75613ce34dfSNamhyung Kim 	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
757454c407eSTom Zanussi 	if (thread == NULL) {
758454c407eSTom Zanussi 		pr_err("problem processing %d event, skipping it.\n",
759454c407eSTom Zanussi 		       event->header.type);
760454c407eSTom Zanussi 		goto repipe;
761454c407eSTom Zanussi 	}
762454c407eSTom Zanussi 
76371a84b5aSArnaldo Carvalho de Melo 	if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {
76463df0e4bSIan Rogers 		struct dso *dso = map__dso(al.map);
76563df0e4bSIan Rogers 
76663df0e4bSIan Rogers 		if (!dso->hit) {
76763df0e4bSIan Rogers 			dso->hit = 1;
76863df0e4bSIan Rogers 			dso__inject_build_id(dso, tool, machine,
769ddee3f2bSIan Rogers 					     sample->cpumode, map__flags(al.map));
770454c407eSTom Zanussi 		}
771454c407eSTom Zanussi 	}
772454c407eSTom Zanussi 
773b91fc39fSArnaldo Carvalho de Melo 	thread__put(thread);
774454c407eSTom Zanussi repipe:
77545694aa7SArnaldo Carvalho de Melo 	perf_event__repipe(tool, event, sample, machine);
7760dd5041cSIan Rogers 	addr_location__exit(&al);
777090f7204SArnaldo Carvalho de Melo 	return 0;
778454c407eSTom Zanussi }
779454c407eSTom Zanussi 
perf_inject__sched_process_exit(struct perf_tool * tool,union perf_event * event __maybe_unused,struct perf_sample * sample,struct evsel * evsel __maybe_unused,struct machine * machine __maybe_unused)78026a031e1SAndrew Vagin static int perf_inject__sched_process_exit(struct perf_tool *tool,
78126a031e1SAndrew Vagin 					   union perf_event *event __maybe_unused,
78226a031e1SAndrew Vagin 					   struct perf_sample *sample,
78332dcd021SJiri Olsa 					   struct evsel *evsel __maybe_unused,
78426a031e1SAndrew Vagin 					   struct machine *machine __maybe_unused)
78526a031e1SAndrew Vagin {
78626a031e1SAndrew Vagin 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
78726a031e1SAndrew Vagin 	struct event_entry *ent;
78826a031e1SAndrew Vagin 
78926a031e1SAndrew Vagin 	list_for_each_entry(ent, &inject->samples, node) {
79026a031e1SAndrew Vagin 		if (sample->tid == ent->tid) {
79126a031e1SAndrew Vagin 			list_del_init(&ent->node);
79226a031e1SAndrew Vagin 			free(ent);
79326a031e1SAndrew Vagin 			break;
79426a031e1SAndrew Vagin 		}
79526a031e1SAndrew Vagin 	}
79626a031e1SAndrew Vagin 
79726a031e1SAndrew Vagin 	return 0;
79826a031e1SAndrew Vagin }
79926a031e1SAndrew Vagin 
perf_inject__sched_switch(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct evsel * evsel,struct machine * machine)80026a031e1SAndrew Vagin static int perf_inject__sched_switch(struct perf_tool *tool,
80126a031e1SAndrew Vagin 				     union perf_event *event,
80226a031e1SAndrew Vagin 				     struct perf_sample *sample,
80332dcd021SJiri Olsa 				     struct evsel *evsel,
80426a031e1SAndrew Vagin 				     struct machine *machine)
80526a031e1SAndrew Vagin {
80626a031e1SAndrew Vagin 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
80726a031e1SAndrew Vagin 	struct event_entry *ent;
80826a031e1SAndrew Vagin 
80926a031e1SAndrew Vagin 	perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
81026a031e1SAndrew Vagin 
81126a031e1SAndrew Vagin 	ent = malloc(event->header.size + sizeof(struct event_entry));
81226a031e1SAndrew Vagin 	if (ent == NULL) {
81326a031e1SAndrew Vagin 		color_fprintf(stderr, PERF_COLOR_RED,
81426a031e1SAndrew Vagin 			     "Not enough memory to process sched switch event!");
81526a031e1SAndrew Vagin 		return -1;
81626a031e1SAndrew Vagin 	}
81726a031e1SAndrew Vagin 
81826a031e1SAndrew Vagin 	ent->tid = sample->tid;
81926a031e1SAndrew Vagin 	memcpy(&ent->event, event, event->header.size);
82026a031e1SAndrew Vagin 	list_add(&ent->node, &inject->samples);
82126a031e1SAndrew Vagin 	return 0;
82226a031e1SAndrew Vagin }
82326a031e1SAndrew Vagin 
824378ef0f5SIan Rogers #ifdef HAVE_LIBTRACEEVENT
perf_inject__sched_stat(struct perf_tool * tool,union perf_event * event __maybe_unused,struct perf_sample * sample,struct evsel * evsel,struct machine * machine)82526a031e1SAndrew Vagin static int perf_inject__sched_stat(struct perf_tool *tool,
82626a031e1SAndrew Vagin 				   union perf_event *event __maybe_unused,
82726a031e1SAndrew Vagin 				   struct perf_sample *sample,
82832dcd021SJiri Olsa 				   struct evsel *evsel,
82926a031e1SAndrew Vagin 				   struct machine *machine)
83026a031e1SAndrew Vagin {
83126a031e1SAndrew Vagin 	struct event_entry *ent;
83226a031e1SAndrew Vagin 	union perf_event *event_sw;
83326a031e1SAndrew Vagin 	struct perf_sample sample_sw;
83426a031e1SAndrew Vagin 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
835efc0cdc9SArnaldo Carvalho de Melo 	u32 pid = evsel__intval(evsel, sample, "pid");
83626a031e1SAndrew Vagin 
83726a031e1SAndrew Vagin 	list_for_each_entry(ent, &inject->samples, node) {
83826a031e1SAndrew Vagin 		if (pid == ent->tid)
83926a031e1SAndrew Vagin 			goto found;
84026a031e1SAndrew Vagin 	}
84126a031e1SAndrew Vagin 
84226a031e1SAndrew Vagin 	return 0;
84326a031e1SAndrew Vagin found:
84426a031e1SAndrew Vagin 	event_sw = &ent->event[0];
8456b6017a2SArnaldo Carvalho de Melo 	evsel__parse_sample(evsel, event_sw, &sample_sw);
84626a031e1SAndrew Vagin 
84726a031e1SAndrew Vagin 	sample_sw.period = sample->period;
84826a031e1SAndrew Vagin 	sample_sw.time	 = sample->time;
8491fc632ceSJiri Olsa 	perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type,
8501fc632ceSJiri Olsa 				      evsel->core.attr.read_format, &sample_sw);
85154a3cf59SAndrew Vagin 	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
85226a031e1SAndrew Vagin 	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
85326a031e1SAndrew Vagin }
854378ef0f5SIan Rogers #endif
85526a031e1SAndrew Vagin 
guest_session__vcpu(struct guest_session * gs,u32 vcpu)85697406a7eSAdrian Hunter static struct guest_vcpu *guest_session__vcpu(struct guest_session *gs, u32 vcpu)
85797406a7eSAdrian Hunter {
85897406a7eSAdrian Hunter 	if (realloc_array_as_needed(gs->vcpu, gs->vcpu_cnt, vcpu, NULL))
85997406a7eSAdrian Hunter 		return NULL;
86097406a7eSAdrian Hunter 	return &gs->vcpu[vcpu];
86197406a7eSAdrian Hunter }
86297406a7eSAdrian Hunter 
guest_session__output_bytes(struct guest_session * gs,void * buf,size_t sz)86397406a7eSAdrian Hunter static int guest_session__output_bytes(struct guest_session *gs, void *buf, size_t sz)
86497406a7eSAdrian Hunter {
86597406a7eSAdrian Hunter 	ssize_t ret = writen(gs->tmp_fd, buf, sz);
86697406a7eSAdrian Hunter 
86797406a7eSAdrian Hunter 	return ret < 0 ? ret : 0;
86897406a7eSAdrian Hunter }
86997406a7eSAdrian Hunter 
guest_session__repipe(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)87097406a7eSAdrian Hunter static int guest_session__repipe(struct perf_tool *tool,
87197406a7eSAdrian Hunter 				 union perf_event *event,
87297406a7eSAdrian Hunter 				 struct perf_sample *sample __maybe_unused,
87397406a7eSAdrian Hunter 				 struct machine *machine __maybe_unused)
87497406a7eSAdrian Hunter {
87597406a7eSAdrian Hunter 	struct guest_session *gs = container_of(tool, struct guest_session, tool);
87697406a7eSAdrian Hunter 
87797406a7eSAdrian Hunter 	return guest_session__output_bytes(gs, event, event->header.size);
87897406a7eSAdrian Hunter }
87997406a7eSAdrian Hunter 
guest_session__map_tid(struct guest_session * gs,u32 tid,u32 vcpu)88097406a7eSAdrian Hunter static int guest_session__map_tid(struct guest_session *gs, u32 tid, u32 vcpu)
88197406a7eSAdrian Hunter {
88297406a7eSAdrian Hunter 	struct guest_tid *guest_tid = zalloc(sizeof(*guest_tid));
88397406a7eSAdrian Hunter 	int hash;
88497406a7eSAdrian Hunter 
88597406a7eSAdrian Hunter 	if (!guest_tid)
88697406a7eSAdrian Hunter 		return -ENOMEM;
88797406a7eSAdrian Hunter 
88897406a7eSAdrian Hunter 	guest_tid->tid = tid;
88997406a7eSAdrian Hunter 	guest_tid->vcpu = vcpu;
89097406a7eSAdrian Hunter 	hash = hash_32(guest_tid->tid, PERF_EVLIST__HLIST_BITS);
89197406a7eSAdrian Hunter 	hlist_add_head(&guest_tid->node, &gs->tids[hash]);
89297406a7eSAdrian Hunter 
89397406a7eSAdrian Hunter 	return 0;
89497406a7eSAdrian Hunter }
89597406a7eSAdrian Hunter 
host_peek_vm_comms_cb(struct perf_session * session __maybe_unused,union perf_event * event,u64 offset __maybe_unused,void * data)89697406a7eSAdrian Hunter static int host_peek_vm_comms_cb(struct perf_session *session __maybe_unused,
89797406a7eSAdrian Hunter 				 union perf_event *event,
89897406a7eSAdrian Hunter 				 u64 offset __maybe_unused, void *data)
89997406a7eSAdrian Hunter {
90097406a7eSAdrian Hunter 	struct guest_session *gs = data;
90197406a7eSAdrian Hunter 	unsigned int vcpu;
90297406a7eSAdrian Hunter 	struct guest_vcpu *guest_vcpu;
90397406a7eSAdrian Hunter 	int ret;
90497406a7eSAdrian Hunter 
90597406a7eSAdrian Hunter 	if (event->header.type != PERF_RECORD_COMM ||
90697406a7eSAdrian Hunter 	    event->comm.pid != gs->machine_pid)
90797406a7eSAdrian Hunter 		return 0;
90897406a7eSAdrian Hunter 
90997406a7eSAdrian Hunter 	/*
91097406a7eSAdrian Hunter 	 * QEMU option -name debug-threads=on, causes thread names formatted as
91197406a7eSAdrian Hunter 	 * below, although it is not an ABI. Also libvirt seems to use this by
91297406a7eSAdrian Hunter 	 * default. Here we rely on it to tell us which thread is which VCPU.
91397406a7eSAdrian Hunter 	 */
91497406a7eSAdrian Hunter 	ret = sscanf(event->comm.comm, "CPU %u/KVM", &vcpu);
91597406a7eSAdrian Hunter 	if (ret <= 0)
91697406a7eSAdrian Hunter 		return ret;
91797406a7eSAdrian Hunter 	pr_debug("Found VCPU: tid %u comm %s vcpu %u\n",
91897406a7eSAdrian Hunter 		 event->comm.tid, event->comm.comm, vcpu);
91997406a7eSAdrian Hunter 	if (vcpu > INT_MAX) {
92097406a7eSAdrian Hunter 		pr_err("Invalid VCPU %u\n", vcpu);
92197406a7eSAdrian Hunter 		return -EINVAL;
92297406a7eSAdrian Hunter 	}
92397406a7eSAdrian Hunter 	guest_vcpu = guest_session__vcpu(gs, vcpu);
92497406a7eSAdrian Hunter 	if (!guest_vcpu)
92597406a7eSAdrian Hunter 		return -ENOMEM;
92697406a7eSAdrian Hunter 	if (guest_vcpu->tid && guest_vcpu->tid != event->comm.tid) {
92797406a7eSAdrian Hunter 		pr_err("Fatal error: Two threads found with the same VCPU\n");
92897406a7eSAdrian Hunter 		return -EINVAL;
92997406a7eSAdrian Hunter 	}
93097406a7eSAdrian Hunter 	guest_vcpu->tid = event->comm.tid;
93197406a7eSAdrian Hunter 
93297406a7eSAdrian Hunter 	return guest_session__map_tid(gs, event->comm.tid, vcpu);
93397406a7eSAdrian Hunter }
93497406a7eSAdrian Hunter 
host_peek_vm_comms(struct perf_session * session,struct guest_session * gs)93597406a7eSAdrian Hunter static int host_peek_vm_comms(struct perf_session *session, struct guest_session *gs)
93697406a7eSAdrian Hunter {
93797406a7eSAdrian Hunter 	return perf_session__peek_events(session, session->header.data_offset,
93897406a7eSAdrian Hunter 					 session->header.data_size,
93997406a7eSAdrian Hunter 					 host_peek_vm_comms_cb, gs);
94097406a7eSAdrian Hunter }
94197406a7eSAdrian Hunter 
evlist__is_id_used(struct evlist * evlist,u64 id)94297406a7eSAdrian Hunter static bool evlist__is_id_used(struct evlist *evlist, u64 id)
94397406a7eSAdrian Hunter {
94497406a7eSAdrian Hunter 	return evlist__id2sid(evlist, id);
94597406a7eSAdrian Hunter }
94697406a7eSAdrian Hunter 
guest_session__allocate_new_id(struct guest_session * gs,struct evlist * host_evlist)94797406a7eSAdrian Hunter static u64 guest_session__allocate_new_id(struct guest_session *gs, struct evlist *host_evlist)
94897406a7eSAdrian Hunter {
94997406a7eSAdrian Hunter 	do {
95097406a7eSAdrian Hunter 		gs->highest_id += 1;
95197406a7eSAdrian Hunter 	} while (!gs->highest_id || evlist__is_id_used(host_evlist, gs->highest_id));
95297406a7eSAdrian Hunter 
95397406a7eSAdrian Hunter 	return gs->highest_id;
95497406a7eSAdrian Hunter }
95597406a7eSAdrian Hunter 
guest_session__map_id(struct guest_session * gs,u64 id,u64 host_id,u32 vcpu)95697406a7eSAdrian Hunter static int guest_session__map_id(struct guest_session *gs, u64 id, u64 host_id, u32 vcpu)
95797406a7eSAdrian Hunter {
95897406a7eSAdrian Hunter 	struct guest_id *guest_id = zalloc(sizeof(*guest_id));
95997406a7eSAdrian Hunter 	int hash;
96097406a7eSAdrian Hunter 
96197406a7eSAdrian Hunter 	if (!guest_id)
96297406a7eSAdrian Hunter 		return -ENOMEM;
96397406a7eSAdrian Hunter 
96497406a7eSAdrian Hunter 	guest_id->id = id;
96597406a7eSAdrian Hunter 	guest_id->host_id = host_id;
96697406a7eSAdrian Hunter 	guest_id->vcpu = vcpu;
96797406a7eSAdrian Hunter 	hash = hash_64(guest_id->id, PERF_EVLIST__HLIST_BITS);
96897406a7eSAdrian Hunter 	hlist_add_head(&guest_id->node, &gs->heads[hash]);
96997406a7eSAdrian Hunter 
97097406a7eSAdrian Hunter 	return 0;
97197406a7eSAdrian Hunter }
97297406a7eSAdrian Hunter 
evlist__find_highest_id(struct evlist * evlist)97397406a7eSAdrian Hunter static u64 evlist__find_highest_id(struct evlist *evlist)
97497406a7eSAdrian Hunter {
97597406a7eSAdrian Hunter 	struct evsel *evsel;
97697406a7eSAdrian Hunter 	u64 highest_id = 1;
97797406a7eSAdrian Hunter 
97897406a7eSAdrian Hunter 	evlist__for_each_entry(evlist, evsel) {
97997406a7eSAdrian Hunter 		u32 j;
98097406a7eSAdrian Hunter 
98197406a7eSAdrian Hunter 		for (j = 0; j < evsel->core.ids; j++) {
98297406a7eSAdrian Hunter 			u64 id = evsel->core.id[j];
98397406a7eSAdrian Hunter 
98497406a7eSAdrian Hunter 			if (id > highest_id)
98597406a7eSAdrian Hunter 				highest_id = id;
98697406a7eSAdrian Hunter 		}
98797406a7eSAdrian Hunter 	}
98897406a7eSAdrian Hunter 
98997406a7eSAdrian Hunter 	return highest_id;
99097406a7eSAdrian Hunter }
99197406a7eSAdrian Hunter 
guest_session__map_ids(struct guest_session * gs,struct evlist * host_evlist)99297406a7eSAdrian Hunter static int guest_session__map_ids(struct guest_session *gs, struct evlist *host_evlist)
99397406a7eSAdrian Hunter {
99497406a7eSAdrian Hunter 	struct evlist *evlist = gs->session->evlist;
99597406a7eSAdrian Hunter 	struct evsel *evsel;
99697406a7eSAdrian Hunter 	int ret;
99797406a7eSAdrian Hunter 
99897406a7eSAdrian Hunter 	evlist__for_each_entry(evlist, evsel) {
99997406a7eSAdrian Hunter 		u32 j;
100097406a7eSAdrian Hunter 
100197406a7eSAdrian Hunter 		for (j = 0; j < evsel->core.ids; j++) {
100297406a7eSAdrian Hunter 			struct perf_sample_id *sid;
100397406a7eSAdrian Hunter 			u64 host_id;
100497406a7eSAdrian Hunter 			u64 id;
100597406a7eSAdrian Hunter 
100697406a7eSAdrian Hunter 			id = evsel->core.id[j];
100797406a7eSAdrian Hunter 			sid = evlist__id2sid(evlist, id);
100897406a7eSAdrian Hunter 			if (!sid || sid->cpu.cpu == -1)
100997406a7eSAdrian Hunter 				continue;
101097406a7eSAdrian Hunter 			host_id = guest_session__allocate_new_id(gs, host_evlist);
101197406a7eSAdrian Hunter 			ret = guest_session__map_id(gs, id, host_id, sid->cpu.cpu);
101297406a7eSAdrian Hunter 			if (ret)
101397406a7eSAdrian Hunter 				return ret;
101497406a7eSAdrian Hunter 		}
101597406a7eSAdrian Hunter 	}
101697406a7eSAdrian Hunter 
101797406a7eSAdrian Hunter 	return 0;
101897406a7eSAdrian Hunter }
101997406a7eSAdrian Hunter 
guest_session__lookup_id(struct guest_session * gs,u64 id)102097406a7eSAdrian Hunter static struct guest_id *guest_session__lookup_id(struct guest_session *gs, u64 id)
102197406a7eSAdrian Hunter {
102297406a7eSAdrian Hunter 	struct hlist_head *head;
102397406a7eSAdrian Hunter 	struct guest_id *guest_id;
102497406a7eSAdrian Hunter 	int hash;
102597406a7eSAdrian Hunter 
102697406a7eSAdrian Hunter 	hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
102797406a7eSAdrian Hunter 	head = &gs->heads[hash];
102897406a7eSAdrian Hunter 
102997406a7eSAdrian Hunter 	hlist_for_each_entry(guest_id, head, node)
103097406a7eSAdrian Hunter 		if (guest_id->id == id)
103197406a7eSAdrian Hunter 			return guest_id;
103297406a7eSAdrian Hunter 
103397406a7eSAdrian Hunter 	return NULL;
103497406a7eSAdrian Hunter }
103597406a7eSAdrian Hunter 
process_attr(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)103697406a7eSAdrian Hunter static int process_attr(struct perf_tool *tool, union perf_event *event,
103797406a7eSAdrian Hunter 			struct perf_sample *sample __maybe_unused,
103897406a7eSAdrian Hunter 			struct machine *machine __maybe_unused)
103997406a7eSAdrian Hunter {
104097406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
104197406a7eSAdrian Hunter 
104297406a7eSAdrian Hunter 	return perf_event__process_attr(tool, event, &inject->session->evlist);
104397406a7eSAdrian Hunter }
104497406a7eSAdrian Hunter 
guest_session__add_attr(struct guest_session * gs,struct evsel * evsel)104597406a7eSAdrian Hunter static int guest_session__add_attr(struct guest_session *gs, struct evsel *evsel)
104697406a7eSAdrian Hunter {
104797406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(gs, struct perf_inject, guest_session);
104897406a7eSAdrian Hunter 	struct perf_event_attr attr = evsel->core.attr;
104997406a7eSAdrian Hunter 	u64 *id_array;
105097406a7eSAdrian Hunter 	u32 *vcpu_array;
105197406a7eSAdrian Hunter 	int ret = -ENOMEM;
105297406a7eSAdrian Hunter 	u32 i;
105397406a7eSAdrian Hunter 
105497406a7eSAdrian Hunter 	id_array = calloc(evsel->core.ids, sizeof(*id_array));
105597406a7eSAdrian Hunter 	if (!id_array)
105697406a7eSAdrian Hunter 		return -ENOMEM;
105797406a7eSAdrian Hunter 
105897406a7eSAdrian Hunter 	vcpu_array = calloc(evsel->core.ids, sizeof(*vcpu_array));
105997406a7eSAdrian Hunter 	if (!vcpu_array)
106097406a7eSAdrian Hunter 		goto out;
106197406a7eSAdrian Hunter 
106297406a7eSAdrian Hunter 	for (i = 0; i < evsel->core.ids; i++) {
106397406a7eSAdrian Hunter 		u64 id = evsel->core.id[i];
106497406a7eSAdrian Hunter 		struct guest_id *guest_id = guest_session__lookup_id(gs, id);
106597406a7eSAdrian Hunter 
106697406a7eSAdrian Hunter 		if (!guest_id) {
106797406a7eSAdrian Hunter 			pr_err("Failed to find guest id %"PRIu64"\n", id);
106897406a7eSAdrian Hunter 			ret = -EINVAL;
106997406a7eSAdrian Hunter 			goto out;
107097406a7eSAdrian Hunter 		}
107197406a7eSAdrian Hunter 		id_array[i] = guest_id->host_id;
107297406a7eSAdrian Hunter 		vcpu_array[i] = guest_id->vcpu;
107397406a7eSAdrian Hunter 	}
107497406a7eSAdrian Hunter 
107597406a7eSAdrian Hunter 	attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
107697406a7eSAdrian Hunter 	attr.exclude_host = 1;
107797406a7eSAdrian Hunter 	attr.exclude_guest = 0;
107897406a7eSAdrian Hunter 
107997406a7eSAdrian Hunter 	ret = perf_event__synthesize_attr(&inject->tool, &attr, evsel->core.ids,
108097406a7eSAdrian Hunter 					  id_array, process_attr);
108197406a7eSAdrian Hunter 	if (ret)
108297406a7eSAdrian Hunter 		pr_err("Failed to add guest attr.\n");
108397406a7eSAdrian Hunter 
108497406a7eSAdrian Hunter 	for (i = 0; i < evsel->core.ids; i++) {
108597406a7eSAdrian Hunter 		struct perf_sample_id *sid;
108697406a7eSAdrian Hunter 		u32 vcpu = vcpu_array[i];
108797406a7eSAdrian Hunter 
108897406a7eSAdrian Hunter 		sid = evlist__id2sid(inject->session->evlist, id_array[i]);
108997406a7eSAdrian Hunter 		/* Guest event is per-thread from the host point of view */
109097406a7eSAdrian Hunter 		sid->cpu.cpu = -1;
109197406a7eSAdrian Hunter 		sid->tid = gs->vcpu[vcpu].tid;
109297406a7eSAdrian Hunter 		sid->machine_pid = gs->machine_pid;
109397406a7eSAdrian Hunter 		sid->vcpu.cpu = vcpu;
109497406a7eSAdrian Hunter 	}
109597406a7eSAdrian Hunter out:
109697406a7eSAdrian Hunter 	free(vcpu_array);
109797406a7eSAdrian Hunter 	free(id_array);
109897406a7eSAdrian Hunter 	return ret;
109997406a7eSAdrian Hunter }
110097406a7eSAdrian Hunter 
guest_session__add_attrs(struct guest_session * gs)110197406a7eSAdrian Hunter static int guest_session__add_attrs(struct guest_session *gs)
110297406a7eSAdrian Hunter {
110397406a7eSAdrian Hunter 	struct evlist *evlist = gs->session->evlist;
110497406a7eSAdrian Hunter 	struct evsel *evsel;
110597406a7eSAdrian Hunter 	int ret;
110697406a7eSAdrian Hunter 
110797406a7eSAdrian Hunter 	evlist__for_each_entry(evlist, evsel) {
110897406a7eSAdrian Hunter 		ret = guest_session__add_attr(gs, evsel);
110997406a7eSAdrian Hunter 		if (ret)
111097406a7eSAdrian Hunter 			return ret;
111197406a7eSAdrian Hunter 	}
111297406a7eSAdrian Hunter 
111397406a7eSAdrian Hunter 	return 0;
111497406a7eSAdrian Hunter }
111597406a7eSAdrian Hunter 
synthesize_id_index(struct perf_inject * inject,size_t new_cnt)111697406a7eSAdrian Hunter static int synthesize_id_index(struct perf_inject *inject, size_t new_cnt)
111797406a7eSAdrian Hunter {
111897406a7eSAdrian Hunter 	struct perf_session *session = inject->session;
111997406a7eSAdrian Hunter 	struct evlist *evlist = session->evlist;
112097406a7eSAdrian Hunter 	struct machine *machine = &session->machines.host;
112197406a7eSAdrian Hunter 	size_t from = evlist->core.nr_entries - new_cnt;
112297406a7eSAdrian Hunter 
112397406a7eSAdrian Hunter 	return __perf_event__synthesize_id_index(&inject->tool, perf_event__repipe,
112497406a7eSAdrian Hunter 						 evlist, machine, from);
112597406a7eSAdrian Hunter }
112697406a7eSAdrian Hunter 
guest_session__lookup_tid(struct guest_session * gs,u32 tid)112797406a7eSAdrian Hunter static struct guest_tid *guest_session__lookup_tid(struct guest_session *gs, u32 tid)
112897406a7eSAdrian Hunter {
112997406a7eSAdrian Hunter 	struct hlist_head *head;
113097406a7eSAdrian Hunter 	struct guest_tid *guest_tid;
113197406a7eSAdrian Hunter 	int hash;
113297406a7eSAdrian Hunter 
113397406a7eSAdrian Hunter 	hash = hash_32(tid, PERF_EVLIST__HLIST_BITS);
113497406a7eSAdrian Hunter 	head = &gs->tids[hash];
113597406a7eSAdrian Hunter 
113697406a7eSAdrian Hunter 	hlist_for_each_entry(guest_tid, head, node)
113797406a7eSAdrian Hunter 		if (guest_tid->tid == tid)
113897406a7eSAdrian Hunter 			return guest_tid;
113997406a7eSAdrian Hunter 
114097406a7eSAdrian Hunter 	return NULL;
114197406a7eSAdrian Hunter }
114297406a7eSAdrian Hunter 
dso__is_in_kernel_space(struct dso * dso)114397406a7eSAdrian Hunter static bool dso__is_in_kernel_space(struct dso *dso)
114497406a7eSAdrian Hunter {
114597406a7eSAdrian Hunter 	if (dso__is_vdso(dso))
114697406a7eSAdrian Hunter 		return false;
114797406a7eSAdrian Hunter 
114897406a7eSAdrian Hunter 	return dso__is_kcore(dso) ||
114997406a7eSAdrian Hunter 	       dso->kernel ||
115097406a7eSAdrian Hunter 	       is_kernel_module(dso->long_name, PERF_RECORD_MISC_CPUMODE_UNKNOWN);
115197406a7eSAdrian Hunter }
115297406a7eSAdrian Hunter 
evlist__first_id(struct evlist * evlist)115397406a7eSAdrian Hunter static u64 evlist__first_id(struct evlist *evlist)
115497406a7eSAdrian Hunter {
115597406a7eSAdrian Hunter 	struct evsel *evsel;
115697406a7eSAdrian Hunter 
115797406a7eSAdrian Hunter 	evlist__for_each_entry(evlist, evsel) {
115897406a7eSAdrian Hunter 		if (evsel->core.ids)
115997406a7eSAdrian Hunter 			return evsel->core.id[0];
116097406a7eSAdrian Hunter 	}
116197406a7eSAdrian Hunter 	return 0;
116297406a7eSAdrian Hunter }
116397406a7eSAdrian Hunter 
process_build_id(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)116497406a7eSAdrian Hunter static int process_build_id(struct perf_tool *tool,
116597406a7eSAdrian Hunter 			    union perf_event *event,
116697406a7eSAdrian Hunter 			    struct perf_sample *sample __maybe_unused,
116797406a7eSAdrian Hunter 			    struct machine *machine __maybe_unused)
116897406a7eSAdrian Hunter {
116997406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
117097406a7eSAdrian Hunter 
117197406a7eSAdrian Hunter 	return perf_event__process_build_id(inject->session, event);
117297406a7eSAdrian Hunter }
117397406a7eSAdrian Hunter 
synthesize_build_id(struct perf_inject * inject,struct dso * dso,pid_t machine_pid)117497406a7eSAdrian Hunter static int synthesize_build_id(struct perf_inject *inject, struct dso *dso, pid_t machine_pid)
117597406a7eSAdrian Hunter {
117697406a7eSAdrian Hunter 	struct machine *machine = perf_session__findnew_machine(inject->session, machine_pid);
117797406a7eSAdrian Hunter 	u8 cpumode = dso__is_in_kernel_space(dso) ?
117897406a7eSAdrian Hunter 			PERF_RECORD_MISC_GUEST_KERNEL :
117997406a7eSAdrian Hunter 			PERF_RECORD_MISC_GUEST_USER;
118097406a7eSAdrian Hunter 
118197406a7eSAdrian Hunter 	if (!machine)
118297406a7eSAdrian Hunter 		return -ENOMEM;
118397406a7eSAdrian Hunter 
118497406a7eSAdrian Hunter 	dso->hit = 1;
118597406a7eSAdrian Hunter 
118697406a7eSAdrian Hunter 	return perf_event__synthesize_build_id(&inject->tool, dso, cpumode,
118797406a7eSAdrian Hunter 					       process_build_id, machine);
118897406a7eSAdrian Hunter }
118997406a7eSAdrian Hunter 
guest_session__add_build_ids(struct guest_session * gs)119097406a7eSAdrian Hunter static int guest_session__add_build_ids(struct guest_session *gs)
119197406a7eSAdrian Hunter {
119297406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(gs, struct perf_inject, guest_session);
119397406a7eSAdrian Hunter 	struct machine *machine = &gs->session->machines.host;
119497406a7eSAdrian Hunter 	struct dso *dso;
119597406a7eSAdrian Hunter 	int ret;
119697406a7eSAdrian Hunter 
119797406a7eSAdrian Hunter 	/* Build IDs will be put in the Build ID feature section */
119897406a7eSAdrian Hunter 	perf_header__set_feat(&inject->session->header, HEADER_BUILD_ID);
119997406a7eSAdrian Hunter 
120097406a7eSAdrian Hunter 	dsos__for_each_with_build_id(dso, &machine->dsos.head) {
120197406a7eSAdrian Hunter 		ret = synthesize_build_id(inject, dso, gs->machine_pid);
120297406a7eSAdrian Hunter 		if (ret)
120397406a7eSAdrian Hunter 			return ret;
120497406a7eSAdrian Hunter 	}
120597406a7eSAdrian Hunter 
120697406a7eSAdrian Hunter 	return 0;
120797406a7eSAdrian Hunter }
120897406a7eSAdrian Hunter 
guest_session__ksymbol_event(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)120997406a7eSAdrian Hunter static int guest_session__ksymbol_event(struct perf_tool *tool,
121097406a7eSAdrian Hunter 					union perf_event *event,
121197406a7eSAdrian Hunter 					struct perf_sample *sample __maybe_unused,
121297406a7eSAdrian Hunter 					struct machine *machine __maybe_unused)
121397406a7eSAdrian Hunter {
121497406a7eSAdrian Hunter 	struct guest_session *gs = container_of(tool, struct guest_session, tool);
121597406a7eSAdrian Hunter 
121697406a7eSAdrian Hunter 	/* Only support out-of-line i.e. no BPF support */
121797406a7eSAdrian Hunter 	if (event->ksymbol.ksym_type != PERF_RECORD_KSYMBOL_TYPE_OOL)
121897406a7eSAdrian Hunter 		return 0;
121997406a7eSAdrian Hunter 
122097406a7eSAdrian Hunter 	return guest_session__output_bytes(gs, event, event->header.size);
122197406a7eSAdrian Hunter }
122297406a7eSAdrian Hunter 
guest_session__start(struct guest_session * gs,const char * name,bool force)122397406a7eSAdrian Hunter static int guest_session__start(struct guest_session *gs, const char *name, bool force)
122497406a7eSAdrian Hunter {
122597406a7eSAdrian Hunter 	char tmp_file_name[] = "/tmp/perf-inject-guest_session-XXXXXX";
122697406a7eSAdrian Hunter 	struct perf_session *session;
122797406a7eSAdrian Hunter 	int ret;
122897406a7eSAdrian Hunter 
122997406a7eSAdrian Hunter 	/* Only these events will be injected */
123097406a7eSAdrian Hunter 	gs->tool.mmap		= guest_session__repipe;
123197406a7eSAdrian Hunter 	gs->tool.mmap2		= guest_session__repipe;
123297406a7eSAdrian Hunter 	gs->tool.comm		= guest_session__repipe;
123397406a7eSAdrian Hunter 	gs->tool.fork		= guest_session__repipe;
123497406a7eSAdrian Hunter 	gs->tool.exit		= guest_session__repipe;
123597406a7eSAdrian Hunter 	gs->tool.lost		= guest_session__repipe;
123697406a7eSAdrian Hunter 	gs->tool.context_switch	= guest_session__repipe;
123797406a7eSAdrian Hunter 	gs->tool.ksymbol	= guest_session__ksymbol_event;
123897406a7eSAdrian Hunter 	gs->tool.text_poke	= guest_session__repipe;
123997406a7eSAdrian Hunter 	/*
124097406a7eSAdrian Hunter 	 * Processing a build ID creates a struct dso with that build ID. Later,
124197406a7eSAdrian Hunter 	 * all guest dsos are iterated and the build IDs processed into the host
124297406a7eSAdrian Hunter 	 * session where they will be output to the Build ID feature section
124397406a7eSAdrian Hunter 	 * when the perf.data file header is written.
124497406a7eSAdrian Hunter 	 */
124597406a7eSAdrian Hunter 	gs->tool.build_id	= perf_event__process_build_id;
124697406a7eSAdrian Hunter 	/* Process the id index to know what VCPU an ID belongs to */
124797406a7eSAdrian Hunter 	gs->tool.id_index	= perf_event__process_id_index;
124897406a7eSAdrian Hunter 
124997406a7eSAdrian Hunter 	gs->tool.ordered_events	= true;
125097406a7eSAdrian Hunter 	gs->tool.ordering_requires_timestamps = true;
125197406a7eSAdrian Hunter 
125297406a7eSAdrian Hunter 	gs->data.path	= name;
125397406a7eSAdrian Hunter 	gs->data.force	= force;
125497406a7eSAdrian Hunter 	gs->data.mode	= PERF_DATA_MODE_READ;
125597406a7eSAdrian Hunter 
125697406a7eSAdrian Hunter 	session = perf_session__new(&gs->data, &gs->tool);
125797406a7eSAdrian Hunter 	if (IS_ERR(session))
125897406a7eSAdrian Hunter 		return PTR_ERR(session);
125997406a7eSAdrian Hunter 	gs->session = session;
126097406a7eSAdrian Hunter 
126197406a7eSAdrian Hunter 	/*
126297406a7eSAdrian Hunter 	 * Initial events have zero'd ID samples. Get default ID sample size
126397406a7eSAdrian Hunter 	 * used for removing them.
126497406a7eSAdrian Hunter 	 */
126597406a7eSAdrian Hunter 	gs->dflt_id_hdr_size = session->machines.host.id_hdr_size;
126697406a7eSAdrian Hunter 	/* And default ID for adding back a host-compatible ID sample */
126797406a7eSAdrian Hunter 	gs->dflt_id = evlist__first_id(session->evlist);
126897406a7eSAdrian Hunter 	if (!gs->dflt_id) {
126997406a7eSAdrian Hunter 		pr_err("Guest data has no sample IDs");
127097406a7eSAdrian Hunter 		return -EINVAL;
127197406a7eSAdrian Hunter 	}
127297406a7eSAdrian Hunter 
127397406a7eSAdrian Hunter 	/* Temporary file for guest events */
127497406a7eSAdrian Hunter 	gs->tmp_file_name = strdup(tmp_file_name);
127597406a7eSAdrian Hunter 	if (!gs->tmp_file_name)
127697406a7eSAdrian Hunter 		return -ENOMEM;
127797406a7eSAdrian Hunter 	gs->tmp_fd = mkstemp(gs->tmp_file_name);
127897406a7eSAdrian Hunter 	if (gs->tmp_fd < 0)
127997406a7eSAdrian Hunter 		return -errno;
128097406a7eSAdrian Hunter 
128197406a7eSAdrian Hunter 	if (zstd_init(&gs->session->zstd_data, 0) < 0)
128297406a7eSAdrian Hunter 		pr_warning("Guest session decompression initialization failed.\n");
128397406a7eSAdrian Hunter 
128497406a7eSAdrian Hunter 	/*
128597406a7eSAdrian Hunter 	 * perf does not support processing 2 sessions simultaneously, so output
128697406a7eSAdrian Hunter 	 * guest events to a temporary file.
128797406a7eSAdrian Hunter 	 */
128897406a7eSAdrian Hunter 	ret = perf_session__process_events(gs->session);
128997406a7eSAdrian Hunter 	if (ret)
129097406a7eSAdrian Hunter 		return ret;
129197406a7eSAdrian Hunter 
129297406a7eSAdrian Hunter 	if (lseek(gs->tmp_fd, 0, SEEK_SET))
129397406a7eSAdrian Hunter 		return -errno;
129497406a7eSAdrian Hunter 
129597406a7eSAdrian Hunter 	return 0;
129697406a7eSAdrian Hunter }
129797406a7eSAdrian Hunter 
129897406a7eSAdrian Hunter /* Free hlist nodes assuming hlist_node is the first member of hlist entries */
free_hlist(struct hlist_head * heads,size_t hlist_sz)129997406a7eSAdrian Hunter static void free_hlist(struct hlist_head *heads, size_t hlist_sz)
130097406a7eSAdrian Hunter {
130197406a7eSAdrian Hunter 	struct hlist_node *pos, *n;
130297406a7eSAdrian Hunter 	size_t i;
130397406a7eSAdrian Hunter 
130497406a7eSAdrian Hunter 	for (i = 0; i < hlist_sz; ++i) {
130597406a7eSAdrian Hunter 		hlist_for_each_safe(pos, n, &heads[i]) {
130697406a7eSAdrian Hunter 			hlist_del(pos);
130797406a7eSAdrian Hunter 			free(pos);
130897406a7eSAdrian Hunter 		}
130997406a7eSAdrian Hunter 	}
131097406a7eSAdrian Hunter }
131197406a7eSAdrian Hunter 
guest_session__exit(struct guest_session * gs)131297406a7eSAdrian Hunter static void guest_session__exit(struct guest_session *gs)
131397406a7eSAdrian Hunter {
131497406a7eSAdrian Hunter 	if (gs->session) {
131597406a7eSAdrian Hunter 		perf_session__delete(gs->session);
131697406a7eSAdrian Hunter 		free_hlist(gs->heads, PERF_EVLIST__HLIST_SIZE);
131797406a7eSAdrian Hunter 		free_hlist(gs->tids, PERF_EVLIST__HLIST_SIZE);
131897406a7eSAdrian Hunter 	}
131997406a7eSAdrian Hunter 	if (gs->tmp_file_name) {
132097406a7eSAdrian Hunter 		if (gs->tmp_fd >= 0)
132197406a7eSAdrian Hunter 			close(gs->tmp_fd);
132297406a7eSAdrian Hunter 		unlink(gs->tmp_file_name);
132379b40a1bSArnaldo Carvalho de Melo 		zfree(&gs->tmp_file_name);
132497406a7eSAdrian Hunter 	}
132579b40a1bSArnaldo Carvalho de Melo 	zfree(&gs->vcpu);
132679b40a1bSArnaldo Carvalho de Melo 	zfree(&gs->perf_data_file);
132797406a7eSAdrian Hunter }
132897406a7eSAdrian Hunter 
get_tsc_conv(struct perf_tsc_conversion * tc,struct perf_record_time_conv * time_conv)132997406a7eSAdrian Hunter static void get_tsc_conv(struct perf_tsc_conversion *tc, struct perf_record_time_conv *time_conv)
133097406a7eSAdrian Hunter {
133197406a7eSAdrian Hunter 	tc->time_shift		= time_conv->time_shift;
133297406a7eSAdrian Hunter 	tc->time_mult		= time_conv->time_mult;
133397406a7eSAdrian Hunter 	tc->time_zero		= time_conv->time_zero;
133497406a7eSAdrian Hunter 	tc->time_cycles		= time_conv->time_cycles;
133597406a7eSAdrian Hunter 	tc->time_mask		= time_conv->time_mask;
133697406a7eSAdrian Hunter 	tc->cap_user_time_zero	= time_conv->cap_user_time_zero;
133797406a7eSAdrian Hunter 	tc->cap_user_time_short	= time_conv->cap_user_time_short;
133897406a7eSAdrian Hunter }
133997406a7eSAdrian Hunter 
guest_session__get_tc(struct guest_session * gs)134097406a7eSAdrian Hunter static void guest_session__get_tc(struct guest_session *gs)
134197406a7eSAdrian Hunter {
134297406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(gs, struct perf_inject, guest_session);
134397406a7eSAdrian Hunter 
134497406a7eSAdrian Hunter 	get_tsc_conv(&gs->host_tc, &inject->session->time_conv);
134597406a7eSAdrian Hunter 	get_tsc_conv(&gs->guest_tc, &gs->session->time_conv);
134697406a7eSAdrian Hunter }
134797406a7eSAdrian Hunter 
guest_session__convert_time(struct guest_session * gs,u64 guest_time,u64 * host_time)134897406a7eSAdrian Hunter static void guest_session__convert_time(struct guest_session *gs, u64 guest_time, u64 *host_time)
134997406a7eSAdrian Hunter {
135097406a7eSAdrian Hunter 	u64 tsc;
135197406a7eSAdrian Hunter 
135297406a7eSAdrian Hunter 	if (!guest_time) {
135397406a7eSAdrian Hunter 		*host_time = 0;
135497406a7eSAdrian Hunter 		return;
135597406a7eSAdrian Hunter 	}
135697406a7eSAdrian Hunter 
135797406a7eSAdrian Hunter 	if (gs->guest_tc.cap_user_time_zero)
135897406a7eSAdrian Hunter 		tsc = perf_time_to_tsc(guest_time, &gs->guest_tc);
135997406a7eSAdrian Hunter 	else
136097406a7eSAdrian Hunter 		tsc = guest_time;
136197406a7eSAdrian Hunter 
136297406a7eSAdrian Hunter 	/*
136397406a7eSAdrian Hunter 	 * This is the correct order of operations for x86 if the TSC Offset and
136497406a7eSAdrian Hunter 	 * Multiplier values are used.
136597406a7eSAdrian Hunter 	 */
136697406a7eSAdrian Hunter 	tsc -= gs->time_offset;
136797406a7eSAdrian Hunter 	tsc /= gs->time_scale;
136897406a7eSAdrian Hunter 
136997406a7eSAdrian Hunter 	if (gs->host_tc.cap_user_time_zero)
137097406a7eSAdrian Hunter 		*host_time = tsc_to_perf_time(tsc, &gs->host_tc);
137197406a7eSAdrian Hunter 	else
137297406a7eSAdrian Hunter 		*host_time = tsc;
137397406a7eSAdrian Hunter }
137497406a7eSAdrian Hunter 
guest_session__fetch(struct guest_session * gs)137597406a7eSAdrian Hunter static int guest_session__fetch(struct guest_session *gs)
137697406a7eSAdrian Hunter {
1377*892d00fbSIan Rogers 	void *buf;
1378*892d00fbSIan Rogers 	struct perf_event_header *hdr;
137997406a7eSAdrian Hunter 	size_t hdr_sz = sizeof(*hdr);
138097406a7eSAdrian Hunter 	ssize_t ret;
138197406a7eSAdrian Hunter 
1382*892d00fbSIan Rogers 	buf = gs->ev.event_buf;
1383*892d00fbSIan Rogers 	if (!buf) {
1384*892d00fbSIan Rogers 		buf = malloc(PERF_SAMPLE_MAX_SIZE);
1385*892d00fbSIan Rogers 		if (!buf)
1386*892d00fbSIan Rogers 			return -ENOMEM;
1387*892d00fbSIan Rogers 		gs->ev.event_buf = buf;
1388*892d00fbSIan Rogers 	}
1389*892d00fbSIan Rogers 	hdr = buf;
139097406a7eSAdrian Hunter 	ret = readn(gs->tmp_fd, buf, hdr_sz);
139197406a7eSAdrian Hunter 	if (ret < 0)
139297406a7eSAdrian Hunter 		return ret;
139397406a7eSAdrian Hunter 
139497406a7eSAdrian Hunter 	if (!ret) {
139597406a7eSAdrian Hunter 		/* Zero size means EOF */
139697406a7eSAdrian Hunter 		hdr->size = 0;
139797406a7eSAdrian Hunter 		return 0;
139897406a7eSAdrian Hunter 	}
139997406a7eSAdrian Hunter 
140097406a7eSAdrian Hunter 	buf += hdr_sz;
140197406a7eSAdrian Hunter 
140297406a7eSAdrian Hunter 	ret = readn(gs->tmp_fd, buf, hdr->size - hdr_sz);
140397406a7eSAdrian Hunter 	if (ret < 0)
140497406a7eSAdrian Hunter 		return ret;
140597406a7eSAdrian Hunter 
140697406a7eSAdrian Hunter 	gs->ev.event = (union perf_event *)gs->ev.event_buf;
140797406a7eSAdrian Hunter 	gs->ev.sample.time = 0;
140897406a7eSAdrian Hunter 
140997406a7eSAdrian Hunter 	if (hdr->type >= PERF_RECORD_USER_TYPE_START) {
141097406a7eSAdrian Hunter 		pr_err("Unexpected type fetching guest event");
141197406a7eSAdrian Hunter 		return 0;
141297406a7eSAdrian Hunter 	}
141397406a7eSAdrian Hunter 
141497406a7eSAdrian Hunter 	ret = evlist__parse_sample(gs->session->evlist, gs->ev.event, &gs->ev.sample);
141597406a7eSAdrian Hunter 	if (ret) {
141697406a7eSAdrian Hunter 		pr_err("Parse failed fetching guest event");
141797406a7eSAdrian Hunter 		return ret;
141897406a7eSAdrian Hunter 	}
141997406a7eSAdrian Hunter 
142097406a7eSAdrian Hunter 	if (!gs->have_tc) {
142197406a7eSAdrian Hunter 		guest_session__get_tc(gs);
142297406a7eSAdrian Hunter 		gs->have_tc = true;
142397406a7eSAdrian Hunter 	}
142497406a7eSAdrian Hunter 
142597406a7eSAdrian Hunter 	guest_session__convert_time(gs, gs->ev.sample.time, &gs->ev.sample.time);
142697406a7eSAdrian Hunter 
142797406a7eSAdrian Hunter 	return 0;
142897406a7eSAdrian Hunter }
142997406a7eSAdrian Hunter 
evlist__append_id_sample(struct evlist * evlist,union perf_event * ev,const struct perf_sample * sample)143097406a7eSAdrian Hunter static int evlist__append_id_sample(struct evlist *evlist, union perf_event *ev,
143197406a7eSAdrian Hunter 				    const struct perf_sample *sample)
143297406a7eSAdrian Hunter {
143397406a7eSAdrian Hunter 	struct evsel *evsel;
143497406a7eSAdrian Hunter 	void *array;
143597406a7eSAdrian Hunter 	int ret;
143697406a7eSAdrian Hunter 
143797406a7eSAdrian Hunter 	evsel = evlist__id2evsel(evlist, sample->id);
143897406a7eSAdrian Hunter 	array = ev;
143997406a7eSAdrian Hunter 
144097406a7eSAdrian Hunter 	if (!evsel) {
144197406a7eSAdrian Hunter 		pr_err("No evsel for id %"PRIu64"\n", sample->id);
144297406a7eSAdrian Hunter 		return -EINVAL;
144397406a7eSAdrian Hunter 	}
144497406a7eSAdrian Hunter 
144597406a7eSAdrian Hunter 	array += ev->header.size;
144697406a7eSAdrian Hunter 	ret = perf_event__synthesize_id_sample(array, evsel->core.attr.sample_type, sample);
144797406a7eSAdrian Hunter 	if (ret < 0)
144897406a7eSAdrian Hunter 		return ret;
144997406a7eSAdrian Hunter 
145097406a7eSAdrian Hunter 	if (ret & 7) {
145197406a7eSAdrian Hunter 		pr_err("Bad id sample size %d\n", ret);
145297406a7eSAdrian Hunter 		return -EINVAL;
145397406a7eSAdrian Hunter 	}
145497406a7eSAdrian Hunter 
145597406a7eSAdrian Hunter 	ev->header.size += ret;
145697406a7eSAdrian Hunter 
145797406a7eSAdrian Hunter 	return 0;
145897406a7eSAdrian Hunter }
145997406a7eSAdrian Hunter 
guest_session__inject_events(struct guest_session * gs,u64 timestamp)146097406a7eSAdrian Hunter static int guest_session__inject_events(struct guest_session *gs, u64 timestamp)
146197406a7eSAdrian Hunter {
146297406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(gs, struct perf_inject, guest_session);
146397406a7eSAdrian Hunter 	int ret;
146497406a7eSAdrian Hunter 
146597406a7eSAdrian Hunter 	if (!gs->ready)
146697406a7eSAdrian Hunter 		return 0;
146797406a7eSAdrian Hunter 
146897406a7eSAdrian Hunter 	while (1) {
146997406a7eSAdrian Hunter 		struct perf_sample *sample;
147097406a7eSAdrian Hunter 		struct guest_id *guest_id;
147197406a7eSAdrian Hunter 		union perf_event *ev;
147297406a7eSAdrian Hunter 		u16 id_hdr_size;
147397406a7eSAdrian Hunter 		u8 cpumode;
147497406a7eSAdrian Hunter 		u64 id;
147597406a7eSAdrian Hunter 
147697406a7eSAdrian Hunter 		if (!gs->fetched) {
147797406a7eSAdrian Hunter 			ret = guest_session__fetch(gs);
147897406a7eSAdrian Hunter 			if (ret)
147997406a7eSAdrian Hunter 				return ret;
148097406a7eSAdrian Hunter 			gs->fetched = true;
148197406a7eSAdrian Hunter 		}
148297406a7eSAdrian Hunter 
148397406a7eSAdrian Hunter 		ev = gs->ev.event;
148497406a7eSAdrian Hunter 		sample = &gs->ev.sample;
148597406a7eSAdrian Hunter 
148697406a7eSAdrian Hunter 		if (!ev->header.size)
148797406a7eSAdrian Hunter 			return 0; /* EOF */
148897406a7eSAdrian Hunter 
148997406a7eSAdrian Hunter 		if (sample->time > timestamp)
149097406a7eSAdrian Hunter 			return 0;
149197406a7eSAdrian Hunter 
149297406a7eSAdrian Hunter 		/* Change cpumode to guest */
149397406a7eSAdrian Hunter 		cpumode = ev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
149497406a7eSAdrian Hunter 		if (cpumode & PERF_RECORD_MISC_USER)
149597406a7eSAdrian Hunter 			cpumode = PERF_RECORD_MISC_GUEST_USER;
149697406a7eSAdrian Hunter 		else
149797406a7eSAdrian Hunter 			cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
149897406a7eSAdrian Hunter 		ev->header.misc &= ~PERF_RECORD_MISC_CPUMODE_MASK;
149997406a7eSAdrian Hunter 		ev->header.misc |= cpumode;
150097406a7eSAdrian Hunter 
150197406a7eSAdrian Hunter 		id = sample->id;
150297406a7eSAdrian Hunter 		if (!id) {
150397406a7eSAdrian Hunter 			id = gs->dflt_id;
150497406a7eSAdrian Hunter 			id_hdr_size = gs->dflt_id_hdr_size;
150597406a7eSAdrian Hunter 		} else {
150697406a7eSAdrian Hunter 			struct evsel *evsel = evlist__id2evsel(gs->session->evlist, id);
150797406a7eSAdrian Hunter 
150897406a7eSAdrian Hunter 			id_hdr_size = evsel__id_hdr_size(evsel);
150997406a7eSAdrian Hunter 		}
151097406a7eSAdrian Hunter 
151197406a7eSAdrian Hunter 		if (id_hdr_size & 7) {
151297406a7eSAdrian Hunter 			pr_err("Bad id_hdr_size %u\n", id_hdr_size);
151397406a7eSAdrian Hunter 			return -EINVAL;
151497406a7eSAdrian Hunter 		}
151597406a7eSAdrian Hunter 
151697406a7eSAdrian Hunter 		if (ev->header.size & 7) {
151797406a7eSAdrian Hunter 			pr_err("Bad event size %u\n", ev->header.size);
151897406a7eSAdrian Hunter 			return -EINVAL;
151997406a7eSAdrian Hunter 		}
152097406a7eSAdrian Hunter 
152197406a7eSAdrian Hunter 		/* Remove guest id sample */
152297406a7eSAdrian Hunter 		ev->header.size -= id_hdr_size;
152397406a7eSAdrian Hunter 
152497406a7eSAdrian Hunter 		if (ev->header.size & 7) {
152597406a7eSAdrian Hunter 			pr_err("Bad raw event size %u\n", ev->header.size);
152697406a7eSAdrian Hunter 			return -EINVAL;
152797406a7eSAdrian Hunter 		}
152897406a7eSAdrian Hunter 
152997406a7eSAdrian Hunter 		guest_id = guest_session__lookup_id(gs, id);
153097406a7eSAdrian Hunter 		if (!guest_id) {
153197406a7eSAdrian Hunter 			pr_err("Guest event with unknown id %llu\n",
153297406a7eSAdrian Hunter 			       (unsigned long long)id);
153397406a7eSAdrian Hunter 			return -EINVAL;
153497406a7eSAdrian Hunter 		}
153597406a7eSAdrian Hunter 
153697406a7eSAdrian Hunter 		/* Change to host ID to avoid conflicting ID values */
153797406a7eSAdrian Hunter 		sample->id = guest_id->host_id;
153897406a7eSAdrian Hunter 		sample->stream_id = guest_id->host_id;
153997406a7eSAdrian Hunter 
154097406a7eSAdrian Hunter 		if (sample->cpu != (u32)-1) {
154197406a7eSAdrian Hunter 			if (sample->cpu >= gs->vcpu_cnt) {
154297406a7eSAdrian Hunter 				pr_err("Guest event with unknown VCPU %u\n",
154397406a7eSAdrian Hunter 				       sample->cpu);
154497406a7eSAdrian Hunter 				return -EINVAL;
154597406a7eSAdrian Hunter 			}
154697406a7eSAdrian Hunter 			/* Change to host CPU instead of guest VCPU */
154797406a7eSAdrian Hunter 			sample->cpu = gs->vcpu[sample->cpu].cpu;
154897406a7eSAdrian Hunter 		}
154997406a7eSAdrian Hunter 
155097406a7eSAdrian Hunter 		/* New id sample with new ID and CPU */
155197406a7eSAdrian Hunter 		ret = evlist__append_id_sample(inject->session->evlist, ev, sample);
155297406a7eSAdrian Hunter 		if (ret)
155397406a7eSAdrian Hunter 			return ret;
155497406a7eSAdrian Hunter 
155597406a7eSAdrian Hunter 		if (ev->header.size & 7) {
155697406a7eSAdrian Hunter 			pr_err("Bad new event size %u\n", ev->header.size);
155797406a7eSAdrian Hunter 			return -EINVAL;
155897406a7eSAdrian Hunter 		}
155997406a7eSAdrian Hunter 
156097406a7eSAdrian Hunter 		gs->fetched = false;
156197406a7eSAdrian Hunter 
156297406a7eSAdrian Hunter 		ret = output_bytes(inject, ev, ev->header.size);
156397406a7eSAdrian Hunter 		if (ret)
156497406a7eSAdrian Hunter 			return ret;
156597406a7eSAdrian Hunter 	}
156697406a7eSAdrian Hunter }
156797406a7eSAdrian Hunter 
guest_session__flush_events(struct guest_session * gs)156897406a7eSAdrian Hunter static int guest_session__flush_events(struct guest_session *gs)
156997406a7eSAdrian Hunter {
157097406a7eSAdrian Hunter 	return guest_session__inject_events(gs, -1);
157197406a7eSAdrian Hunter }
157297406a7eSAdrian Hunter 
host__repipe(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)157397406a7eSAdrian Hunter static int host__repipe(struct perf_tool *tool,
157497406a7eSAdrian Hunter 			union perf_event *event,
157597406a7eSAdrian Hunter 			struct perf_sample *sample,
157697406a7eSAdrian Hunter 			struct machine *machine)
157797406a7eSAdrian Hunter {
157897406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
157997406a7eSAdrian Hunter 	int ret;
158097406a7eSAdrian Hunter 
158197406a7eSAdrian Hunter 	ret = guest_session__inject_events(&inject->guest_session, sample->time);
158297406a7eSAdrian Hunter 	if (ret)
158397406a7eSAdrian Hunter 		return ret;
158497406a7eSAdrian Hunter 
158597406a7eSAdrian Hunter 	return perf_event__repipe(tool, event, sample, machine);
158697406a7eSAdrian Hunter }
158797406a7eSAdrian Hunter 
host__finished_init(struct perf_session * session,union perf_event * event)158897406a7eSAdrian Hunter static int host__finished_init(struct perf_session *session, union perf_event *event)
158997406a7eSAdrian Hunter {
159097406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(session->tool, struct perf_inject, tool);
159197406a7eSAdrian Hunter 	struct guest_session *gs = &inject->guest_session;
159297406a7eSAdrian Hunter 	int ret;
159397406a7eSAdrian Hunter 
159497406a7eSAdrian Hunter 	/*
159597406a7eSAdrian Hunter 	 * Peek through host COMM events to find QEMU threads and the VCPU they
159697406a7eSAdrian Hunter 	 * are running.
159797406a7eSAdrian Hunter 	 */
159897406a7eSAdrian Hunter 	ret = host_peek_vm_comms(session, gs);
159997406a7eSAdrian Hunter 	if (ret)
160097406a7eSAdrian Hunter 		return ret;
160197406a7eSAdrian Hunter 
160297406a7eSAdrian Hunter 	if (!gs->vcpu_cnt) {
16038147f79eSColin Ian King 		pr_err("No VCPU threads found for pid %u\n", gs->machine_pid);
160497406a7eSAdrian Hunter 		return -EINVAL;
160597406a7eSAdrian Hunter 	}
160697406a7eSAdrian Hunter 
160797406a7eSAdrian Hunter 	/*
160897406a7eSAdrian Hunter 	 * Allocate new (unused) host sample IDs and map them to the guest IDs.
160997406a7eSAdrian Hunter 	 */
161097406a7eSAdrian Hunter 	gs->highest_id = evlist__find_highest_id(session->evlist);
161197406a7eSAdrian Hunter 	ret = guest_session__map_ids(gs, session->evlist);
161297406a7eSAdrian Hunter 	if (ret)
161397406a7eSAdrian Hunter 		return ret;
161497406a7eSAdrian Hunter 
161597406a7eSAdrian Hunter 	ret = guest_session__add_attrs(gs);
161697406a7eSAdrian Hunter 	if (ret)
161797406a7eSAdrian Hunter 		return ret;
161897406a7eSAdrian Hunter 
161997406a7eSAdrian Hunter 	ret = synthesize_id_index(inject, gs->session->evlist->core.nr_entries);
162097406a7eSAdrian Hunter 	if (ret) {
162197406a7eSAdrian Hunter 		pr_err("Failed to synthesize id_index\n");
162297406a7eSAdrian Hunter 		return ret;
162397406a7eSAdrian Hunter 	}
162497406a7eSAdrian Hunter 
162597406a7eSAdrian Hunter 	ret = guest_session__add_build_ids(gs);
162697406a7eSAdrian Hunter 	if (ret) {
162797406a7eSAdrian Hunter 		pr_err("Failed to add guest build IDs\n");
162897406a7eSAdrian Hunter 		return ret;
162997406a7eSAdrian Hunter 	}
163097406a7eSAdrian Hunter 
163197406a7eSAdrian Hunter 	gs->ready = true;
163297406a7eSAdrian Hunter 
163397406a7eSAdrian Hunter 	ret = guest_session__inject_events(gs, 0);
163497406a7eSAdrian Hunter 	if (ret)
163597406a7eSAdrian Hunter 		return ret;
163697406a7eSAdrian Hunter 
163797406a7eSAdrian Hunter 	return perf_event__repipe_op2_synth(session, event);
163897406a7eSAdrian Hunter }
163997406a7eSAdrian Hunter 
164097406a7eSAdrian Hunter /*
164197406a7eSAdrian Hunter  * Obey finished-round ordering. The FINISHED_ROUND event is first processed
164297406a7eSAdrian Hunter  * which flushes host events to file up until the last flush time. Then inject
164397406a7eSAdrian Hunter  * guest events up to the same time. Finally write out the FINISHED_ROUND event
164497406a7eSAdrian Hunter  * itself.
164597406a7eSAdrian Hunter  */
host__finished_round(struct perf_tool * tool,union perf_event * event,struct ordered_events * oe)164697406a7eSAdrian Hunter static int host__finished_round(struct perf_tool *tool,
164797406a7eSAdrian Hunter 				union perf_event *event,
164897406a7eSAdrian Hunter 				struct ordered_events *oe)
164997406a7eSAdrian Hunter {
165097406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
165197406a7eSAdrian Hunter 	int ret = perf_event__process_finished_round(tool, event, oe);
165297406a7eSAdrian Hunter 	u64 timestamp = ordered_events__last_flush_time(oe);
165397406a7eSAdrian Hunter 
165497406a7eSAdrian Hunter 	if (ret)
165597406a7eSAdrian Hunter 		return ret;
165697406a7eSAdrian Hunter 
165797406a7eSAdrian Hunter 	ret = guest_session__inject_events(&inject->guest_session, timestamp);
165897406a7eSAdrian Hunter 	if (ret)
165997406a7eSAdrian Hunter 		return ret;
166097406a7eSAdrian Hunter 
166197406a7eSAdrian Hunter 	return perf_event__repipe_oe_synth(tool, event, oe);
166297406a7eSAdrian Hunter }
166397406a7eSAdrian Hunter 
host__context_switch(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)166497406a7eSAdrian Hunter static int host__context_switch(struct perf_tool *tool,
166597406a7eSAdrian Hunter 				union perf_event *event,
166697406a7eSAdrian Hunter 				struct perf_sample *sample,
166797406a7eSAdrian Hunter 				struct machine *machine)
166897406a7eSAdrian Hunter {
166997406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
167097406a7eSAdrian Hunter 	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
167197406a7eSAdrian Hunter 	struct guest_session *gs = &inject->guest_session;
167297406a7eSAdrian Hunter 	u32 pid = event->context_switch.next_prev_pid;
167397406a7eSAdrian Hunter 	u32 tid = event->context_switch.next_prev_tid;
167497406a7eSAdrian Hunter 	struct guest_tid *guest_tid;
167597406a7eSAdrian Hunter 	u32 vcpu;
167697406a7eSAdrian Hunter 
167797406a7eSAdrian Hunter 	if (out || pid != gs->machine_pid)
167897406a7eSAdrian Hunter 		goto out;
167997406a7eSAdrian Hunter 
168097406a7eSAdrian Hunter 	guest_tid = guest_session__lookup_tid(gs, tid);
168197406a7eSAdrian Hunter 	if (!guest_tid)
168297406a7eSAdrian Hunter 		goto out;
168397406a7eSAdrian Hunter 
168497406a7eSAdrian Hunter 	if (sample->cpu == (u32)-1) {
168597406a7eSAdrian Hunter 		pr_err("Switch event does not have CPU\n");
168697406a7eSAdrian Hunter 		return -EINVAL;
168797406a7eSAdrian Hunter 	}
168897406a7eSAdrian Hunter 
168997406a7eSAdrian Hunter 	vcpu = guest_tid->vcpu;
169097406a7eSAdrian Hunter 	if (vcpu >= gs->vcpu_cnt)
169197406a7eSAdrian Hunter 		return -EINVAL;
169297406a7eSAdrian Hunter 
169397406a7eSAdrian Hunter 	/* Guest is switching in, record which CPU the VCPU is now running on */
169497406a7eSAdrian Hunter 	gs->vcpu[vcpu].cpu = sample->cpu;
169597406a7eSAdrian Hunter out:
169697406a7eSAdrian Hunter 	return host__repipe(tool, event, sample, machine);
169797406a7eSAdrian Hunter }
169897406a7eSAdrian Hunter 
sig_handler(int sig __maybe_unused)16995ded57acSArnaldo Carvalho de Melo static void sig_handler(int sig __maybe_unused)
17005ded57acSArnaldo Carvalho de Melo {
17015ded57acSArnaldo Carvalho de Melo 	session_done = 1;
17025ded57acSArnaldo Carvalho de Melo }
17035ded57acSArnaldo Carvalho de Melo 
evsel__check_stype(struct evsel * evsel,u64 sample_type,const char * sample_msg)1704b14b36d0SArnaldo Carvalho de Melo static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg)
170526a031e1SAndrew Vagin {
17061fc632ceSJiri Olsa 	struct perf_event_attr *attr = &evsel->core.attr;
17078ab2e96dSArnaldo Carvalho de Melo 	const char *name = evsel__name(evsel);
170826a031e1SAndrew Vagin 
170926a031e1SAndrew Vagin 	if (!(attr->sample_type & sample_type)) {
171026a031e1SAndrew Vagin 		pr_err("Samples for %s event do not have %s attribute set.",
171126a031e1SAndrew Vagin 			name, sample_msg);
171226a031e1SAndrew Vagin 		return -EINVAL;
171326a031e1SAndrew Vagin 	}
171426a031e1SAndrew Vagin 
171526a031e1SAndrew Vagin 	return 0;
171626a031e1SAndrew Vagin }
171726a031e1SAndrew Vagin 
drop_sample(struct perf_tool * tool __maybe_unused,union perf_event * event __maybe_unused,struct perf_sample * sample __maybe_unused,struct evsel * evsel __maybe_unused,struct machine * machine __maybe_unused)1718f56fb986SAdrian Hunter static int drop_sample(struct perf_tool *tool __maybe_unused,
1719f56fb986SAdrian Hunter 		       union perf_event *event __maybe_unused,
1720f56fb986SAdrian Hunter 		       struct perf_sample *sample __maybe_unused,
172132dcd021SJiri Olsa 		       struct evsel *evsel __maybe_unused,
1722f56fb986SAdrian Hunter 		       struct machine *machine __maybe_unused)
1723f56fb986SAdrian Hunter {
1724f56fb986SAdrian Hunter 	return 0;
1725f56fb986SAdrian Hunter }
1726f56fb986SAdrian Hunter 
strip_init(struct perf_inject * inject)1727f56fb986SAdrian Hunter static void strip_init(struct perf_inject *inject)
1728f56fb986SAdrian Hunter {
172963503dbaSJiri Olsa 	struct evlist *evlist = inject->session->evlist;
173032dcd021SJiri Olsa 	struct evsel *evsel;
1731f56fb986SAdrian Hunter 
1732f56fb986SAdrian Hunter 	inject->tool.context_switch = perf_event__drop;
1733f56fb986SAdrian Hunter 
1734e5cadb93SArnaldo Carvalho de Melo 	evlist__for_each_entry(evlist, evsel)
1735f56fb986SAdrian Hunter 		evsel->handler = drop_sample;
1736f56fb986SAdrian Hunter }
1737f56fb986SAdrian Hunter 
parse_vm_time_correlation(const struct option * opt,const char * str,int unset)173883d7f5f1SAdrian Hunter static int parse_vm_time_correlation(const struct option *opt, const char *str, int unset)
173983d7f5f1SAdrian Hunter {
174083d7f5f1SAdrian Hunter 	struct perf_inject *inject = opt->value;
174183d7f5f1SAdrian Hunter 	const char *args;
174283d7f5f1SAdrian Hunter 	char *dry_run;
174383d7f5f1SAdrian Hunter 
174483d7f5f1SAdrian Hunter 	if (unset)
174583d7f5f1SAdrian Hunter 		return 0;
174683d7f5f1SAdrian Hunter 
174783d7f5f1SAdrian Hunter 	inject->itrace_synth_opts.set = true;
174883d7f5f1SAdrian Hunter 	inject->itrace_synth_opts.vm_time_correlation = true;
174983d7f5f1SAdrian Hunter 	inject->in_place_update = true;
175083d7f5f1SAdrian Hunter 
175183d7f5f1SAdrian Hunter 	if (!str)
175283d7f5f1SAdrian Hunter 		return 0;
175383d7f5f1SAdrian Hunter 
175483d7f5f1SAdrian Hunter 	dry_run = skip_spaces(str);
175583d7f5f1SAdrian Hunter 	if (!strncmp(dry_run, "dry-run", strlen("dry-run"))) {
175683d7f5f1SAdrian Hunter 		inject->itrace_synth_opts.vm_tm_corr_dry_run = true;
175783d7f5f1SAdrian Hunter 		inject->in_place_update_dry_run = true;
175883d7f5f1SAdrian Hunter 		args = dry_run + strlen("dry-run");
175983d7f5f1SAdrian Hunter 	} else {
176083d7f5f1SAdrian Hunter 		args = str;
176183d7f5f1SAdrian Hunter 	}
176283d7f5f1SAdrian Hunter 
176383d7f5f1SAdrian Hunter 	inject->itrace_synth_opts.vm_tm_corr_args = strdup(args);
176483d7f5f1SAdrian Hunter 
176583d7f5f1SAdrian Hunter 	return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
176683d7f5f1SAdrian Hunter }
176783d7f5f1SAdrian Hunter 
parse_guest_data(const struct option * opt,const char * str,int unset)176897406a7eSAdrian Hunter static int parse_guest_data(const struct option *opt, const char *str, int unset)
176997406a7eSAdrian Hunter {
177097406a7eSAdrian Hunter 	struct perf_inject *inject = opt->value;
177197406a7eSAdrian Hunter 	struct guest_session *gs = &inject->guest_session;
177297406a7eSAdrian Hunter 	char *tok;
177397406a7eSAdrian Hunter 	char *s;
177497406a7eSAdrian Hunter 
177597406a7eSAdrian Hunter 	if (unset)
177697406a7eSAdrian Hunter 		return 0;
177797406a7eSAdrian Hunter 
177897406a7eSAdrian Hunter 	if (!str)
177997406a7eSAdrian Hunter 		goto bad_args;
178097406a7eSAdrian Hunter 
178197406a7eSAdrian Hunter 	s = strdup(str);
178297406a7eSAdrian Hunter 	if (!s)
178397406a7eSAdrian Hunter 		return -ENOMEM;
178497406a7eSAdrian Hunter 
178597406a7eSAdrian Hunter 	gs->perf_data_file = strsep(&s, ",");
178697406a7eSAdrian Hunter 	if (!gs->perf_data_file)
178797406a7eSAdrian Hunter 		goto bad_args;
178897406a7eSAdrian Hunter 
178997406a7eSAdrian Hunter 	gs->copy_kcore_dir = has_kcore_dir(gs->perf_data_file);
179097406a7eSAdrian Hunter 	if (gs->copy_kcore_dir)
179197406a7eSAdrian Hunter 		inject->output.is_dir = true;
179297406a7eSAdrian Hunter 
179397406a7eSAdrian Hunter 	tok = strsep(&s, ",");
179497406a7eSAdrian Hunter 	if (!tok)
179597406a7eSAdrian Hunter 		goto bad_args;
179697406a7eSAdrian Hunter 	gs->machine_pid = strtoul(tok, NULL, 0);
179797406a7eSAdrian Hunter 	if (!inject->guest_session.machine_pid)
179897406a7eSAdrian Hunter 		goto bad_args;
179997406a7eSAdrian Hunter 
180097406a7eSAdrian Hunter 	gs->time_scale = 1;
180197406a7eSAdrian Hunter 
180297406a7eSAdrian Hunter 	tok = strsep(&s, ",");
180397406a7eSAdrian Hunter 	if (!tok)
180497406a7eSAdrian Hunter 		goto out;
180597406a7eSAdrian Hunter 	gs->time_offset = strtoull(tok, NULL, 0);
180697406a7eSAdrian Hunter 
180797406a7eSAdrian Hunter 	tok = strsep(&s, ",");
180897406a7eSAdrian Hunter 	if (!tok)
180997406a7eSAdrian Hunter 		goto out;
181097406a7eSAdrian Hunter 	gs->time_scale = strtod(tok, NULL);
181197406a7eSAdrian Hunter 	if (!gs->time_scale)
181297406a7eSAdrian Hunter 		goto bad_args;
181397406a7eSAdrian Hunter out:
181497406a7eSAdrian Hunter 	return 0;
181597406a7eSAdrian Hunter 
181697406a7eSAdrian Hunter bad_args:
181797406a7eSAdrian Hunter 	pr_err("--guest-data option requires guest perf.data file name, "
181897406a7eSAdrian Hunter 	       "guest machine PID, and optionally guest timestamp offset, "
181997406a7eSAdrian Hunter 	       "and guest timestamp scale factor, separated by commas.\n");
182097406a7eSAdrian Hunter 	return -1;
182197406a7eSAdrian Hunter }
182297406a7eSAdrian Hunter 
save_section_info_cb(struct perf_file_section * section,struct perf_header * ph __maybe_unused,int feat,int fd __maybe_unused,void * data)1823180b3d06SAdrian Hunter static int save_section_info_cb(struct perf_file_section *section,
1824180b3d06SAdrian Hunter 				struct perf_header *ph __maybe_unused,
1825180b3d06SAdrian Hunter 				int feat, int fd __maybe_unused, void *data)
1826180b3d06SAdrian Hunter {
1827180b3d06SAdrian Hunter 	struct perf_inject *inject = data;
1828180b3d06SAdrian Hunter 
1829180b3d06SAdrian Hunter 	inject->secs[feat] = *section;
1830180b3d06SAdrian Hunter 	return 0;
1831180b3d06SAdrian Hunter }
1832180b3d06SAdrian Hunter 
save_section_info(struct perf_inject * inject)1833180b3d06SAdrian Hunter static int save_section_info(struct perf_inject *inject)
1834180b3d06SAdrian Hunter {
1835180b3d06SAdrian Hunter 	struct perf_header *header = &inject->session->header;
1836180b3d06SAdrian Hunter 	int fd = perf_data__fd(inject->session->data);
1837180b3d06SAdrian Hunter 
1838180b3d06SAdrian Hunter 	return perf_header__process_sections(header, fd, inject, save_section_info_cb);
1839180b3d06SAdrian Hunter }
1840180b3d06SAdrian Hunter 
keep_feat(int feat)1841180b3d06SAdrian Hunter static bool keep_feat(int feat)
1842180b3d06SAdrian Hunter {
1843180b3d06SAdrian Hunter 	switch (feat) {
1844180b3d06SAdrian Hunter 	/* Keep original information that describes the machine or software */
1845180b3d06SAdrian Hunter 	case HEADER_TRACING_DATA:
1846180b3d06SAdrian Hunter 	case HEADER_HOSTNAME:
1847180b3d06SAdrian Hunter 	case HEADER_OSRELEASE:
1848180b3d06SAdrian Hunter 	case HEADER_VERSION:
1849180b3d06SAdrian Hunter 	case HEADER_ARCH:
1850180b3d06SAdrian Hunter 	case HEADER_NRCPUS:
1851180b3d06SAdrian Hunter 	case HEADER_CPUDESC:
1852180b3d06SAdrian Hunter 	case HEADER_CPUID:
1853180b3d06SAdrian Hunter 	case HEADER_TOTAL_MEM:
1854180b3d06SAdrian Hunter 	case HEADER_CPU_TOPOLOGY:
1855180b3d06SAdrian Hunter 	case HEADER_NUMA_TOPOLOGY:
1856180b3d06SAdrian Hunter 	case HEADER_PMU_MAPPINGS:
1857180b3d06SAdrian Hunter 	case HEADER_CACHE:
1858180b3d06SAdrian Hunter 	case HEADER_MEM_TOPOLOGY:
1859180b3d06SAdrian Hunter 	case HEADER_CLOCKID:
1860180b3d06SAdrian Hunter 	case HEADER_BPF_PROG_INFO:
1861180b3d06SAdrian Hunter 	case HEADER_BPF_BTF:
1862180b3d06SAdrian Hunter 	case HEADER_CPU_PMU_CAPS:
1863180b3d06SAdrian Hunter 	case HEADER_CLOCK_DATA:
1864180b3d06SAdrian Hunter 	case HEADER_HYBRID_TOPOLOGY:
18652139f742SRavi Bangoria 	case HEADER_PMU_CAPS:
1866180b3d06SAdrian Hunter 		return true;
1867180b3d06SAdrian Hunter 	/* Information that can be updated */
1868180b3d06SAdrian Hunter 	case HEADER_BUILD_ID:
1869180b3d06SAdrian Hunter 	case HEADER_CMDLINE:
1870180b3d06SAdrian Hunter 	case HEADER_EVENT_DESC:
1871180b3d06SAdrian Hunter 	case HEADER_BRANCH_STACK:
1872180b3d06SAdrian Hunter 	case HEADER_GROUP_DESC:
1873180b3d06SAdrian Hunter 	case HEADER_AUXTRACE:
1874180b3d06SAdrian Hunter 	case HEADER_STAT:
1875180b3d06SAdrian Hunter 	case HEADER_SAMPLE_TIME:
1876180b3d06SAdrian Hunter 	case HEADER_DIR_FORMAT:
1877180b3d06SAdrian Hunter 	case HEADER_COMPRESSED:
1878180b3d06SAdrian Hunter 	default:
1879180b3d06SAdrian Hunter 		return false;
1880180b3d06SAdrian Hunter 	};
1881180b3d06SAdrian Hunter }
1882180b3d06SAdrian Hunter 
read_file(int fd,u64 offs,void * buf,size_t sz)1883180b3d06SAdrian Hunter static int read_file(int fd, u64 offs, void *buf, size_t sz)
1884180b3d06SAdrian Hunter {
1885180b3d06SAdrian Hunter 	ssize_t ret = preadn(fd, buf, sz, offs);
1886180b3d06SAdrian Hunter 
1887180b3d06SAdrian Hunter 	if (ret < 0)
1888180b3d06SAdrian Hunter 		return -errno;
1889180b3d06SAdrian Hunter 	if ((size_t)ret != sz)
1890180b3d06SAdrian Hunter 		return -EINVAL;
1891180b3d06SAdrian Hunter 	return 0;
1892180b3d06SAdrian Hunter }
1893180b3d06SAdrian Hunter 
feat_copy(struct perf_inject * inject,int feat,struct feat_writer * fw)1894180b3d06SAdrian Hunter static int feat_copy(struct perf_inject *inject, int feat, struct feat_writer *fw)
1895180b3d06SAdrian Hunter {
1896180b3d06SAdrian Hunter 	int fd = perf_data__fd(inject->session->data);
1897180b3d06SAdrian Hunter 	u64 offs = inject->secs[feat].offset;
1898180b3d06SAdrian Hunter 	size_t sz = inject->secs[feat].size;
1899180b3d06SAdrian Hunter 	void *buf = malloc(sz);
1900180b3d06SAdrian Hunter 	int ret;
1901180b3d06SAdrian Hunter 
1902180b3d06SAdrian Hunter 	if (!buf)
1903180b3d06SAdrian Hunter 		return -ENOMEM;
1904180b3d06SAdrian Hunter 
1905180b3d06SAdrian Hunter 	ret = read_file(fd, offs, buf, sz);
1906180b3d06SAdrian Hunter 	if (ret)
1907180b3d06SAdrian Hunter 		goto out_free;
1908180b3d06SAdrian Hunter 
1909180b3d06SAdrian Hunter 	ret = fw->write(fw, buf, sz);
1910180b3d06SAdrian Hunter out_free:
1911180b3d06SAdrian Hunter 	free(buf);
1912180b3d06SAdrian Hunter 	return ret;
1913180b3d06SAdrian Hunter }
1914180b3d06SAdrian Hunter 
1915180b3d06SAdrian Hunter struct inject_fc {
1916180b3d06SAdrian Hunter 	struct feat_copier fc;
1917180b3d06SAdrian Hunter 	struct perf_inject *inject;
1918180b3d06SAdrian Hunter };
1919180b3d06SAdrian Hunter 
feat_copy_cb(struct feat_copier * fc,int feat,struct feat_writer * fw)1920180b3d06SAdrian Hunter static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw)
1921180b3d06SAdrian Hunter {
1922180b3d06SAdrian Hunter 	struct inject_fc *inj_fc = container_of(fc, struct inject_fc, fc);
1923180b3d06SAdrian Hunter 	struct perf_inject *inject = inj_fc->inject;
1924180b3d06SAdrian Hunter 	int ret;
1925180b3d06SAdrian Hunter 
1926180b3d06SAdrian Hunter 	if (!inject->secs[feat].offset ||
1927180b3d06SAdrian Hunter 	    !keep_feat(feat))
1928180b3d06SAdrian Hunter 		return 0;
1929180b3d06SAdrian Hunter 
1930180b3d06SAdrian Hunter 	ret = feat_copy(inject, feat, fw);
1931180b3d06SAdrian Hunter 	if (ret < 0)
1932180b3d06SAdrian Hunter 		return ret;
1933180b3d06SAdrian Hunter 
1934180b3d06SAdrian Hunter 	return 1; /* Feature section copied */
1935180b3d06SAdrian Hunter }
1936180b3d06SAdrian Hunter 
copy_kcore_dir(struct perf_inject * inject)1937d8fc0855SAdrian Hunter static int copy_kcore_dir(struct perf_inject *inject)
1938d8fc0855SAdrian Hunter {
1939d8fc0855SAdrian Hunter 	char *cmd;
1940d8fc0855SAdrian Hunter 	int ret;
1941d8fc0855SAdrian Hunter 
1942d8fc0855SAdrian Hunter 	ret = asprintf(&cmd, "cp -r -n %s/kcore_dir* %s >/dev/null 2>&1",
1943d8fc0855SAdrian Hunter 		       inject->input_name, inject->output.path);
1944d8fc0855SAdrian Hunter 	if (ret < 0)
1945d8fc0855SAdrian Hunter 		return ret;
1946d8fc0855SAdrian Hunter 	pr_debug("%s\n", cmd);
1947342cb0d8SAdrian Hunter 	ret = system(cmd);
1948342cb0d8SAdrian Hunter 	free(cmd);
1949342cb0d8SAdrian Hunter 	return ret;
1950d8fc0855SAdrian Hunter }
1951d8fc0855SAdrian Hunter 
guest_session__copy_kcore_dir(struct guest_session * gs)195297406a7eSAdrian Hunter static int guest_session__copy_kcore_dir(struct guest_session *gs)
195397406a7eSAdrian Hunter {
195497406a7eSAdrian Hunter 	struct perf_inject *inject = container_of(gs, struct perf_inject, guest_session);
195597406a7eSAdrian Hunter 	char *cmd;
195697406a7eSAdrian Hunter 	int ret;
195797406a7eSAdrian Hunter 
195897406a7eSAdrian Hunter 	ret = asprintf(&cmd, "cp -r -n %s/kcore_dir %s/kcore_dir__%u >/dev/null 2>&1",
195997406a7eSAdrian Hunter 		       gs->perf_data_file, inject->output.path, gs->machine_pid);
196097406a7eSAdrian Hunter 	if (ret < 0)
196197406a7eSAdrian Hunter 		return ret;
196297406a7eSAdrian Hunter 	pr_debug("%s\n", cmd);
196397406a7eSAdrian Hunter 	ret = system(cmd);
196497406a7eSAdrian Hunter 	free(cmd);
196597406a7eSAdrian Hunter 	return ret;
196697406a7eSAdrian Hunter }
196797406a7eSAdrian Hunter 
output_fd(struct perf_inject * inject)1968c271a55bSAdrian Hunter static int output_fd(struct perf_inject *inject)
1969c271a55bSAdrian Hunter {
1970c271a55bSAdrian Hunter 	return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
1971c271a55bSAdrian Hunter }
1972c271a55bSAdrian Hunter 
__cmd_inject(struct perf_inject * inject)19735ded57acSArnaldo Carvalho de Melo static int __cmd_inject(struct perf_inject *inject)
19745ded57acSArnaldo Carvalho de Melo {
19755ded57acSArnaldo Carvalho de Melo 	int ret = -EINVAL;
197697406a7eSAdrian Hunter 	struct guest_session *gs = &inject->guest_session;
19771cb8bdccSNamhyung Kim 	struct perf_session *session = inject->session;
1978c271a55bSAdrian Hunter 	int fd = output_fd(inject);
19790f0aa5e0SAdrian Hunter 	u64 output_data_offset;
19805ded57acSArnaldo Carvalho de Melo 
19815ded57acSArnaldo Carvalho de Melo 	signal(SIGINT, sig_handler);
19825ded57acSArnaldo Carvalho de Melo 
19830f0aa5e0SAdrian Hunter 	if (inject->build_ids || inject->sched_stat ||
198427c9c342SNamhyung Kim 	    inject->itrace_synth_opts.set || inject->build_id_all) {
19855ded57acSArnaldo Carvalho de Melo 		inject->tool.mmap	  = perf_event__repipe_mmap;
19865c5e854bSStephane Eranian 		inject->tool.mmap2	  = perf_event__repipe_mmap2;
1987f62d3f0fSArnaldo Carvalho de Melo 		inject->tool.fork	  = perf_event__repipe_fork;
1988378ef0f5SIan Rogers #ifdef HAVE_LIBTRACEEVENT
19895ded57acSArnaldo Carvalho de Melo 		inject->tool.tracing_data = perf_event__repipe_tracing_data;
1990378ef0f5SIan Rogers #endif
19915ded57acSArnaldo Carvalho de Melo 	}
19925ded57acSArnaldo Carvalho de Melo 
199337ed2cddSRaul Silvera 	output_data_offset = perf_session__data_offset(session->evlist);
19940f0aa5e0SAdrian Hunter 
199527c9c342SNamhyung Kim 	if (inject->build_id_all) {
199627c9c342SNamhyung Kim 		inject->tool.mmap	  = perf_event__repipe_buildid_mmap;
199727c9c342SNamhyung Kim 		inject->tool.mmap2	  = perf_event__repipe_buildid_mmap2;
199827c9c342SNamhyung Kim 	} else if (inject->build_ids) {
199954a3cf59SAndrew Vagin 		inject->tool.sample = perf_event__inject_buildid;
200054a3cf59SAndrew Vagin 	} else if (inject->sched_stat) {
200132dcd021SJiri Olsa 		struct evsel *evsel;
200226a031e1SAndrew Vagin 
2003e5cadb93SArnaldo Carvalho de Melo 		evlist__for_each_entry(session->evlist, evsel) {
20048ab2e96dSArnaldo Carvalho de Melo 			const char *name = evsel__name(evsel);
200526a031e1SAndrew Vagin 
200626a031e1SAndrew Vagin 			if (!strcmp(name, "sched:sched_switch")) {
2007b14b36d0SArnaldo Carvalho de Melo 				if (evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
200826a031e1SAndrew Vagin 					return -EINVAL;
200926a031e1SAndrew Vagin 
2010744a9719SArnaldo Carvalho de Melo 				evsel->handler = perf_inject__sched_switch;
201126a031e1SAndrew Vagin 			} else if (!strcmp(name, "sched:sched_process_exit"))
2012744a9719SArnaldo Carvalho de Melo 				evsel->handler = perf_inject__sched_process_exit;
2013378ef0f5SIan Rogers #ifdef HAVE_LIBTRACEEVENT
201426a031e1SAndrew Vagin 			else if (!strncmp(name, "sched:sched_stat_", 17))
2015744a9719SArnaldo Carvalho de Melo 				evsel->handler = perf_inject__sched_stat;
2016378ef0f5SIan Rogers #endif
201726a031e1SAndrew Vagin 		}
201883d7f5f1SAdrian Hunter 	} else if (inject->itrace_synth_opts.vm_time_correlation) {
201983d7f5f1SAdrian Hunter 		session->itrace_synth_opts = &inject->itrace_synth_opts;
202083d7f5f1SAdrian Hunter 		memset(&inject->tool, 0, sizeof(inject->tool));
202183d7f5f1SAdrian Hunter 		inject->tool.id_index	    = perf_event__process_id_index;
202283d7f5f1SAdrian Hunter 		inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
202383d7f5f1SAdrian Hunter 		inject->tool.auxtrace	    = perf_event__process_auxtrace;
202483d7f5f1SAdrian Hunter 		inject->tool.auxtrace_error = perf_event__process_auxtrace_error;
202583d7f5f1SAdrian Hunter 		inject->tool.ordered_events = true;
202683d7f5f1SAdrian Hunter 		inject->tool.ordering_requires_timestamps = true;
20270f0aa5e0SAdrian Hunter 	} else if (inject->itrace_synth_opts.set) {
20280f0aa5e0SAdrian Hunter 		session->itrace_synth_opts = &inject->itrace_synth_opts;
20290f0aa5e0SAdrian Hunter 		inject->itrace_synth_opts.inject = true;
20300f0aa5e0SAdrian Hunter 		inject->tool.comm	    = perf_event__repipe_comm;
2031f3b3614aSHari Bathini 		inject->tool.namespaces	    = perf_event__repipe_namespaces;
20320f0aa5e0SAdrian Hunter 		inject->tool.exit	    = perf_event__repipe_exit;
203329f6eecaSAdrian Hunter 		inject->tool.id_index	    = perf_event__process_id_index;
20340f0aa5e0SAdrian Hunter 		inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
20350f0aa5e0SAdrian Hunter 		inject->tool.auxtrace	    = perf_event__process_auxtrace;
203673117308SAdrian Hunter 		inject->tool.aux	    = perf_event__drop_aux;
203761750473SAdrian Hunter 		inject->tool.itrace_start   = perf_event__drop_aux;
203861750473SAdrian Hunter 		inject->tool.aux_output_hw_id = perf_event__drop_aux;
20390f0aa5e0SAdrian Hunter 		inject->tool.ordered_events = true;
20400f0aa5e0SAdrian Hunter 		inject->tool.ordering_requires_timestamps = true;
20410f0aa5e0SAdrian Hunter 		/* Allow space in the header for new attributes */
2042c29d9792SAdrian Hunter 		output_data_offset = roundup(8192 + session->header.data_offset, 4096);
2043f56fb986SAdrian Hunter 		if (inject->strip)
2044f56fb986SAdrian Hunter 			strip_init(inject);
204597406a7eSAdrian Hunter 	} else if (gs->perf_data_file) {
204697406a7eSAdrian Hunter 		char *name = gs->perf_data_file;
204797406a7eSAdrian Hunter 
204897406a7eSAdrian Hunter 		/*
204997406a7eSAdrian Hunter 		 * Not strictly necessary, but keep these events in order wrt
205097406a7eSAdrian Hunter 		 * guest events.
205197406a7eSAdrian Hunter 		 */
205297406a7eSAdrian Hunter 		inject->tool.mmap		= host__repipe;
205397406a7eSAdrian Hunter 		inject->tool.mmap2		= host__repipe;
205497406a7eSAdrian Hunter 		inject->tool.comm		= host__repipe;
205597406a7eSAdrian Hunter 		inject->tool.fork		= host__repipe;
205697406a7eSAdrian Hunter 		inject->tool.exit		= host__repipe;
205797406a7eSAdrian Hunter 		inject->tool.lost		= host__repipe;
205897406a7eSAdrian Hunter 		inject->tool.context_switch	= host__repipe;
205997406a7eSAdrian Hunter 		inject->tool.ksymbol		= host__repipe;
206097406a7eSAdrian Hunter 		inject->tool.text_poke		= host__repipe;
206197406a7eSAdrian Hunter 		/*
206297406a7eSAdrian Hunter 		 * Once the host session has initialized, set up sample ID
206397406a7eSAdrian Hunter 		 * mapping and feed in guest attrs, build IDs and initial
206497406a7eSAdrian Hunter 		 * events.
206597406a7eSAdrian Hunter 		 */
206697406a7eSAdrian Hunter 		inject->tool.finished_init	= host__finished_init;
206797406a7eSAdrian Hunter 		/* Obey finished round ordering */
206897406a7eSAdrian Hunter 		inject->tool.finished_round	= host__finished_round,
206997406a7eSAdrian Hunter 		/* Keep track of which CPU a VCPU is runnng on */
207097406a7eSAdrian Hunter 		inject->tool.context_switch	= host__context_switch;
207197406a7eSAdrian Hunter 		/*
207297406a7eSAdrian Hunter 		 * Must order events to be able to obey finished round
207397406a7eSAdrian Hunter 		 * ordering.
207497406a7eSAdrian Hunter 		 */
207597406a7eSAdrian Hunter 		inject->tool.ordered_events	= true;
207697406a7eSAdrian Hunter 		inject->tool.ordering_requires_timestamps = true;
207797406a7eSAdrian Hunter 		/* Set up a separate session to process guest perf.data file */
207897406a7eSAdrian Hunter 		ret = guest_session__start(gs, name, session->data->force);
207997406a7eSAdrian Hunter 		if (ret) {
208097406a7eSAdrian Hunter 			pr_err("Failed to process %s, error %d\n", name, ret);
208197406a7eSAdrian Hunter 			return ret;
208297406a7eSAdrian Hunter 		}
208397406a7eSAdrian Hunter 		/* Allow space in the header for guest attributes */
208497406a7eSAdrian Hunter 		output_data_offset += gs->session->header.data_offset;
208597406a7eSAdrian Hunter 		output_data_offset = roundup(output_data_offset, 4096);
208626a031e1SAndrew Vagin 	}
208726a031e1SAndrew Vagin 
208899fa2984SAdrian Hunter 	if (!inject->itrace_synth_opts.set)
208999fa2984SAdrian Hunter 		auxtrace_index__free(&session->auxtrace_index);
209099fa2984SAdrian Hunter 
2091fea20d66SNamhyung Kim 	if (!inject->is_pipe && !inject->in_place_update)
20920f0aa5e0SAdrian Hunter 		lseek(fd, output_data_offset, SEEK_SET);
2093e558a5bdSAndrew Vagin 
2094b7b61cbeSArnaldo Carvalho de Melo 	ret = perf_session__process_events(session);
2095bb8d521fSDavid Carrillo-Cisneros 	if (ret)
2096bb8d521fSDavid Carrillo-Cisneros 		return ret;
20975ded57acSArnaldo Carvalho de Melo 
209897406a7eSAdrian Hunter 	if (gs->session) {
209997406a7eSAdrian Hunter 		/*
210097406a7eSAdrian Hunter 		 * Remaining guest events have later timestamps. Flush them
210197406a7eSAdrian Hunter 		 * out to file.
210297406a7eSAdrian Hunter 		 */
210397406a7eSAdrian Hunter 		ret = guest_session__flush_events(gs);
210497406a7eSAdrian Hunter 		if (ret) {
210597406a7eSAdrian Hunter 			pr_err("Failed to flush guest events\n");
210697406a7eSAdrian Hunter 			return ret;
210797406a7eSAdrian Hunter 		}
210897406a7eSAdrian Hunter 	}
210997406a7eSAdrian Hunter 
2110fea20d66SNamhyung Kim 	if (!inject->is_pipe && !inject->in_place_update) {
2111180b3d06SAdrian Hunter 		struct inject_fc inj_fc = {
2112180b3d06SAdrian Hunter 			.fc.copy = feat_copy_cb,
2113180b3d06SAdrian Hunter 			.inject = inject,
2114180b3d06SAdrian Hunter 		};
2115180b3d06SAdrian Hunter 
2116640dad47SAdrian Hunter 		if (inject->build_ids)
2117e38b43c3SAdrian Hunter 			perf_header__set_feat(&session->header,
2118e38b43c3SAdrian Hunter 					      HEADER_BUILD_ID);
2119640dad47SAdrian Hunter 		/*
2120640dad47SAdrian Hunter 		 * Keep all buildids when there is unprocessed AUX data because
2121640dad47SAdrian Hunter 		 * it is not known which ones the AUX trace hits.
2122640dad47SAdrian Hunter 		 */
2123640dad47SAdrian Hunter 		if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
2124640dad47SAdrian Hunter 		    inject->have_auxtrace && !inject->itrace_synth_opts.set)
2125cd10b289SAdrian Hunter 			dsos__hit_all(session);
21260f0aa5e0SAdrian Hunter 		/*
21270f0aa5e0SAdrian Hunter 		 * The AUX areas have been removed and replaced with
21281c756cd4SAl Grant 		 * synthesized hardware events, so clear the feature flag.
21290f0aa5e0SAdrian Hunter 		 */
2130051a01b9SAdrian Hunter 		if (inject->itrace_synth_opts.set) {
21310f0aa5e0SAdrian Hunter 			perf_header__clear_feat(&session->header,
21320f0aa5e0SAdrian Hunter 						HEADER_AUXTRACE);
2133ec90e42cSAdrian Hunter 			if (inject->itrace_synth_opts.last_branch ||
2134ec90e42cSAdrian Hunter 			    inject->itrace_synth_opts.add_last_branch)
2135051a01b9SAdrian Hunter 				perf_header__set_feat(&session->header,
2136051a01b9SAdrian Hunter 						      HEADER_BRANCH_STACK);
2137051a01b9SAdrian Hunter 		}
21380f0aa5e0SAdrian Hunter 		session->header.data_offset = output_data_offset;
2139e558a5bdSAndrew Vagin 		session->header.data_size = inject->bytes_written;
2140180b3d06SAdrian Hunter 		perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc);
2141d8fc0855SAdrian Hunter 
2142d8fc0855SAdrian Hunter 		if (inject->copy_kcore_dir) {
2143d8fc0855SAdrian Hunter 			ret = copy_kcore_dir(inject);
214497406a7eSAdrian Hunter 			if (ret) {
214597406a7eSAdrian Hunter 				pr_err("Failed to copy kcore\n");
2146d8fc0855SAdrian Hunter 				return ret;
2147d8fc0855SAdrian Hunter 			}
2148e558a5bdSAndrew Vagin 		}
214997406a7eSAdrian Hunter 		if (gs->copy_kcore_dir) {
215097406a7eSAdrian Hunter 			ret = guest_session__copy_kcore_dir(gs);
215197406a7eSAdrian Hunter 			if (ret) {
215297406a7eSAdrian Hunter 				pr_err("Failed to copy guest kcore\n");
215397406a7eSAdrian Hunter 				return ret;
215497406a7eSAdrian Hunter 			}
215597406a7eSAdrian Hunter 		}
215697406a7eSAdrian Hunter 	}
2157e558a5bdSAndrew Vagin 
21585ded57acSArnaldo Carvalho de Melo 	return ret;
21595ded57acSArnaldo Carvalho de Melo }
21605ded57acSArnaldo Carvalho de Melo 
cmd_inject(int argc,const char ** argv)2161b0ad8ea6SArnaldo Carvalho de Melo int cmd_inject(int argc, const char **argv)
21625ded57acSArnaldo Carvalho de Melo {
21635ded57acSArnaldo Carvalho de Melo 	struct perf_inject inject = {
21645ded57acSArnaldo Carvalho de Melo 		.tool = {
21659e69c210SArnaldo Carvalho de Melo 			.sample		= perf_event__repipe_sample,
21662946ecedSNamhyung Kim 			.read		= perf_event__repipe_sample,
21678115d60cSArnaldo Carvalho de Melo 			.mmap		= perf_event__repipe,
21685c5e854bSStephane Eranian 			.mmap2		= perf_event__repipe,
21698115d60cSArnaldo Carvalho de Melo 			.comm		= perf_event__repipe,
21702946ecedSNamhyung Kim 			.namespaces	= perf_event__repipe,
21712946ecedSNamhyung Kim 			.cgroup		= perf_event__repipe,
21728115d60cSArnaldo Carvalho de Melo 			.fork		= perf_event__repipe,
21738115d60cSArnaldo Carvalho de Melo 			.exit		= perf_event__repipe,
21748115d60cSArnaldo Carvalho de Melo 			.lost		= perf_event__repipe,
2175d8145b3eSAdrian Hunter 			.lost_samples	= perf_event__repipe,
21764a96f7a0SAdrian Hunter 			.aux		= perf_event__repipe,
21770ad21f68SAdrian Hunter 			.itrace_start	= perf_event__repipe,
217861750473SAdrian Hunter 			.aux_output_hw_id = perf_event__repipe,
21790286039fSAdrian Hunter 			.context_switch	= perf_event__repipe,
21808115d60cSArnaldo Carvalho de Melo 			.throttle	= perf_event__repipe,
21818115d60cSArnaldo Carvalho de Melo 			.unthrottle	= perf_event__repipe,
21822946ecedSNamhyung Kim 			.ksymbol	= perf_event__repipe,
21832946ecedSNamhyung Kim 			.bpf		= perf_event__repipe,
21842946ecedSNamhyung Kim 			.text_poke	= perf_event__repipe,
218510d0f086SArnaldo Carvalho de Melo 			.attr		= perf_event__repipe_attr,
21862946ecedSNamhyung Kim 			.event_update	= perf_event__repipe_event_update,
218747c3d109SAdrian Hunter 			.tracing_data	= perf_event__repipe_op2_synth,
2188d704ebdaSArnaldo Carvalho de Melo 			.finished_round	= perf_event__repipe_oe_synth,
2189743eb868SArnaldo Carvalho de Melo 			.build_id	= perf_event__repipe_op2_synth,
21903c659eedSAdrian Hunter 			.id_index	= perf_event__repipe_op2_synth,
21912946ecedSNamhyung Kim 			.auxtrace_info	= perf_event__repipe_op2_synth,
21922946ecedSNamhyung Kim 			.auxtrace_error	= perf_event__repipe_op2_synth,
21932946ecedSNamhyung Kim 			.time_conv	= perf_event__repipe_op2_synth,
21942946ecedSNamhyung Kim 			.thread_map	= perf_event__repipe_op2_synth,
21952946ecedSNamhyung Kim 			.cpu_map	= perf_event__repipe_op2_synth,
21962946ecedSNamhyung Kim 			.stat_config	= perf_event__repipe_op2_synth,
21972946ecedSNamhyung Kim 			.stat		= perf_event__repipe_op2_synth,
21982946ecedSNamhyung Kim 			.stat_round	= perf_event__repipe_op2_synth,
2199e9def1b2SDavid Carrillo-Cisneros 			.feature	= perf_event__repipe_op2_synth,
22003812d298SAdrian Hunter 			.finished_init	= perf_event__repipe_op2_synth,
22012946ecedSNamhyung Kim 			.compressed	= perf_event__repipe_op4_synth,
22022946ecedSNamhyung Kim 			.auxtrace	= perf_event__repipe_auxtrace,
22035ded57acSArnaldo Carvalho de Melo 		},
2204e558a5bdSAndrew Vagin 		.input_name  = "-",
220526a031e1SAndrew Vagin 		.samples = LIST_HEAD_INIT(inject.samples),
22063406912cSJiri Olsa 		.output = {
22073406912cSJiri Olsa 			.path = "-",
22083406912cSJiri Olsa 			.mode = PERF_DATA_MODE_WRITE,
220960136667SNamhyung Kim 			.use_stdio = true,
22103406912cSJiri Olsa 		},
2211454c407eSTom Zanussi 	};
22128ceb41d7SJiri Olsa 	struct perf_data data = {
22131cb8bdccSNamhyung Kim 		.mode = PERF_DATA_MODE_READ,
221460136667SNamhyung Kim 		.use_stdio = true,
22151cb8bdccSNamhyung Kim 	};
22161cb8bdccSNamhyung Kim 	int ret;
2217c3a057dcSNamhyung Kim 	bool repipe = true;
22188012243eSRaul Silvera 	const char *known_build_ids = NULL;
22191cb8bdccSNamhyung Kim 
22209b07e27fSStephane Eranian 	struct option options[] = {
22215ded57acSArnaldo Carvalho de Melo 		OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
2222454c407eSTom Zanussi 			    "Inject build-ids into the output stream"),
222327c9c342SNamhyung Kim 		OPT_BOOLEAN(0, "buildid-all", &inject.build_id_all,
222427c9c342SNamhyung Kim 			    "Inject build-ids of all DSOs into the output stream"),
22258012243eSRaul Silvera 		OPT_STRING(0, "known-build-ids", &known_build_ids,
22268012243eSRaul Silvera 			   "buildid path [,buildid path...]",
22278012243eSRaul Silvera 			   "build-ids to use for given paths"),
2228e558a5bdSAndrew Vagin 		OPT_STRING('i', "input", &inject.input_name, "file",
2229e558a5bdSAndrew Vagin 			   "input file name"),
22302d4f2799SJiri Olsa 		OPT_STRING('o', "output", &inject.output.path, "file",
2231e558a5bdSAndrew Vagin 			   "output file name"),
223226a031e1SAndrew Vagin 		OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
223326a031e1SAndrew Vagin 			    "Merge sched-stat and sched-switch for getting events "
223426a031e1SAndrew Vagin 			    "where and how long tasks slept"),
2235e12b202fSJiri Olsa #ifdef HAVE_JITDUMP
22369b07e27fSStephane Eranian 		OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
2237e12b202fSJiri Olsa #endif
2238454c407eSTom Zanussi 		OPT_INCR('v', "verbose", &verbose,
2239454c407eSTom Zanussi 			 "be more verbose (show build ids, etc)"),
2240b3a018fcSJames Clark 		OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
2241b3a018fcSJames Clark 			   "file", "vmlinux pathname"),
2242b3a018fcSJames Clark 		OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
2243b3a018fcSJames Clark 			    "don't load vmlinux even if found"),
2244a7a2b8b4SAdrian Hunter 		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
2245a7a2b8b4SAdrian Hunter 			   "kallsyms pathname"),
22468ceb41d7SJiri Olsa 		OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
22470f0aa5e0SAdrian Hunter 		OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
2248c12e039dSAndi Kleen 				    NULL, "opts", "Instruction Tracing options\n"
2249c12e039dSAndi Kleen 				    ITRACE_HELP,
22500f0aa5e0SAdrian Hunter 				    itrace_parse_synth_opts),
2251f56fb986SAdrian Hunter 		OPT_BOOLEAN(0, "strip", &inject.strip,
2252f56fb986SAdrian Hunter 			    "strip non-synthesized events (use with --itrace)"),
225383d7f5f1SAdrian Hunter 		OPT_CALLBACK_OPTARG(0, "vm-time-correlation", &inject, NULL, "opts",
225483d7f5f1SAdrian Hunter 				    "correlate time between VM guests and the host",
225583d7f5f1SAdrian Hunter 				    parse_vm_time_correlation),
225697406a7eSAdrian Hunter 		OPT_CALLBACK_OPTARG(0, "guest-data", &inject, NULL, "opts",
225797406a7eSAdrian Hunter 				    "inject events from a guest perf.data file",
225897406a7eSAdrian Hunter 				    parse_guest_data),
225997406a7eSAdrian Hunter 		OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
226097406a7eSAdrian Hunter 			   "guest mount directory under which every guest os"
226197406a7eSAdrian Hunter 			   " instance has a subdir"),
2262454c407eSTom Zanussi 		OPT_END()
2263454c407eSTom Zanussi 	};
2264002439e8SArnaldo Carvalho de Melo 	const char * const inject_usage[] = {
2265002439e8SArnaldo Carvalho de Melo 		"perf inject [<options>]",
2266002439e8SArnaldo Carvalho de Melo 		NULL
2267002439e8SArnaldo Carvalho de Melo 	};
2268e12b202fSJiri Olsa #ifndef HAVE_JITDUMP
22699b07e27fSStephane Eranian 	set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
22709b07e27fSStephane Eranian #endif
2271002439e8SArnaldo Carvalho de Melo 	argc = parse_options(argc, argv, options, inject_usage, 0);
2272454c407eSTom Zanussi 
2273454c407eSTom Zanussi 	/*
2274454c407eSTom Zanussi 	 * Any (unrecognized) arguments left?
2275454c407eSTom Zanussi 	 */
2276454c407eSTom Zanussi 	if (argc)
2277002439e8SArnaldo Carvalho de Melo 		usage_with_options(inject_usage, options);
2278454c407eSTom Zanussi 
2279f56fb986SAdrian Hunter 	if (inject.strip && !inject.itrace_synth_opts.set) {
2280f56fb986SAdrian Hunter 		pr_err("--strip option requires --itrace option\n");
2281f56fb986SAdrian Hunter 		return -1;
2282f56fb986SAdrian Hunter 	}
2283f56fb986SAdrian Hunter 
2284b3a018fcSJames Clark 	if (symbol__validate_sym_arguments())
2285b3a018fcSJames Clark 		return -1;
2286b3a018fcSJames Clark 
22872a525f6aSAdrian Hunter 	if (inject.in_place_update) {
22882a525f6aSAdrian Hunter 		if (!strcmp(inject.input_name, "-")) {
22892a525f6aSAdrian Hunter 			pr_err("Input file name required for in-place updating\n");
22902a525f6aSAdrian Hunter 			return -1;
22912a525f6aSAdrian Hunter 		}
22922a525f6aSAdrian Hunter 		if (strcmp(inject.output.path, "-")) {
22932a525f6aSAdrian Hunter 			pr_err("Output file name must not be specified for in-place updating\n");
22942a525f6aSAdrian Hunter 			return -1;
22952a525f6aSAdrian Hunter 		}
22962a525f6aSAdrian Hunter 		if (!data.force && !inject.in_place_update_dry_run) {
22972a525f6aSAdrian Hunter 			pr_err("The input file would be updated in place, "
22982a525f6aSAdrian Hunter 				"the --force option is required.\n");
22992a525f6aSAdrian Hunter 			return -1;
23002a525f6aSAdrian Hunter 		}
23012a525f6aSAdrian Hunter 		if (!inject.in_place_update_dry_run)
23022a525f6aSAdrian Hunter 			data.in_place_update = true;
2303d8fc0855SAdrian Hunter 	} else {
2304d8fc0855SAdrian Hunter 		if (strcmp(inject.output.path, "-") && !inject.strip &&
2305d8fc0855SAdrian Hunter 		    has_kcore_dir(inject.input_name)) {
2306d8fc0855SAdrian Hunter 			inject.output.is_dir = true;
2307d8fc0855SAdrian Hunter 			inject.copy_kcore_dir = true;
2308d8fc0855SAdrian Hunter 		}
2309d8fc0855SAdrian Hunter 		if (perf_data__open(&inject.output)) {
2310e558a5bdSAndrew Vagin 			perror("failed to create output file");
2311e558a5bdSAndrew Vagin 			return -1;
2312e558a5bdSAndrew Vagin 		}
2313d8fc0855SAdrian Hunter 	}
2314e558a5bdSAndrew Vagin 
23152d4f2799SJiri Olsa 	data.path = inject.input_name;
2316c3a057dcSNamhyung Kim 	if (!strcmp(inject.input_name, "-") || inject.output.is_pipe) {
2317fea20d66SNamhyung Kim 		inject.is_pipe = true;
2318c3a057dcSNamhyung Kim 		/*
2319c3a057dcSNamhyung Kim 		 * Do not repipe header when input is a regular file
2320c3a057dcSNamhyung Kim 		 * since either it can rewrite the header at the end
2321c3a057dcSNamhyung Kim 		 * or write a new pipe header.
2322c3a057dcSNamhyung Kim 		 */
2323c3a057dcSNamhyung Kim 		if (strcmp(inject.input_name, "-"))
2324c3a057dcSNamhyung Kim 			repipe = false;
2325c3a057dcSNamhyung Kim 	}
2326fea20d66SNamhyung Kim 
2327c3a057dcSNamhyung Kim 	inject.session = __perf_session__new(&data, repipe,
2328c271a55bSAdrian Hunter 					     output_fd(&inject),
2329fea20d66SNamhyung Kim 					     &inject.tool);
233002e6246fSRiccardo Mancini 	if (IS_ERR(inject.session)) {
233102e6246fSRiccardo Mancini 		ret = PTR_ERR(inject.session);
233202e6246fSRiccardo Mancini 		goto out_close_output;
233302e6246fSRiccardo Mancini 	}
23341cb8bdccSNamhyung Kim 
2335371a3378SAlexey Budankov 	if (zstd_init(&(inject.session->zstd_data), 0) < 0)
2336371a3378SAlexey Budankov 		pr_warning("Decompression initialization failed.\n");
2337371a3378SAlexey Budankov 
2338180b3d06SAdrian Hunter 	/* Save original section info before feature bits change */
2339180b3d06SAdrian Hunter 	ret = save_section_info(&inject);
2340180b3d06SAdrian Hunter 	if (ret)
2341180b3d06SAdrian Hunter 		goto out_delete;
2342180b3d06SAdrian Hunter 
2343c3a057dcSNamhyung Kim 	if (!data.is_pipe && inject.output.is_pipe) {
2344c3a057dcSNamhyung Kim 		ret = perf_header__write_pipe(perf_data__fd(&inject.output));
2345c3a057dcSNamhyung Kim 		if (ret < 0) {
2346c3a057dcSNamhyung Kim 			pr_err("Couldn't write a new pipe header.\n");
2347c3a057dcSNamhyung Kim 			goto out_delete;
2348c3a057dcSNamhyung Kim 		}
2349c3a057dcSNamhyung Kim 
2350c3a057dcSNamhyung Kim 		ret = perf_event__synthesize_for_pipe(&inject.tool,
2351c3a057dcSNamhyung Kim 						      inject.session,
2352c3a057dcSNamhyung Kim 						      &inject.output,
2353c3a057dcSNamhyung Kim 						      perf_event__repipe);
2354c3a057dcSNamhyung Kim 		if (ret < 0)
2355c3a057dcSNamhyung Kim 			goto out_delete;
2356c3a057dcSNamhyung Kim 	}
2357c3a057dcSNamhyung Kim 
235827c9c342SNamhyung Kim 	if (inject.build_ids && !inject.build_id_all) {
2359921f3fadSArnaldo Carvalho de Melo 		/*
2360921f3fadSArnaldo Carvalho de Melo 		 * to make sure the mmap records are ordered correctly
2361921f3fadSArnaldo Carvalho de Melo 		 * and so that the correct especially due to jitted code
2362921f3fadSArnaldo Carvalho de Melo 		 * mmaps. We cannot generate the buildid hit list and
2363921f3fadSArnaldo Carvalho de Melo 		 * inject the jit mmaps at the same time for now.
2364921f3fadSArnaldo Carvalho de Melo 		 */
2365921f3fadSArnaldo Carvalho de Melo 		inject.tool.ordered_events = true;
2366921f3fadSArnaldo Carvalho de Melo 		inject.tool.ordering_requires_timestamps = true;
23678012243eSRaul Silvera 		if (known_build_ids != NULL) {
23688012243eSRaul Silvera 			inject.known_build_ids =
23698012243eSRaul Silvera 				perf_inject__parse_known_build_ids(known_build_ids);
23708012243eSRaul Silvera 
23718012243eSRaul Silvera 			if (inject.known_build_ids == NULL) {
23728012243eSRaul Silvera 				pr_err("Couldn't parse known build ids.\n");
23738012243eSRaul Silvera 				goto out_delete;
23748012243eSRaul Silvera 			}
23758012243eSRaul Silvera 		}
2376921f3fadSArnaldo Carvalho de Melo 	}
237727c9c342SNamhyung Kim 
237827c9c342SNamhyung Kim 	if (inject.sched_stat) {
237927c9c342SNamhyung Kim 		inject.tool.ordered_events = true;
238027c9c342SNamhyung Kim 	}
238127c9c342SNamhyung Kim 
2382e12b202fSJiri Olsa #ifdef HAVE_JITDUMP
23839b07e27fSStephane Eranian 	if (inject.jit_mode) {
23849b07e27fSStephane Eranian 		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
23859b07e27fSStephane Eranian 		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
23869b07e27fSStephane Eranian 		inject.tool.ordered_events = true;
23879b07e27fSStephane Eranian 		inject.tool.ordering_requires_timestamps = true;
23889b07e27fSStephane Eranian 		/*
23899b07e27fSStephane Eranian 		 * JIT MMAP injection injects all MMAP events in one go, so it
23909b07e27fSStephane Eranian 		 * does not obey finished_round semantics.
23919b07e27fSStephane Eranian 		 */
23929b07e27fSStephane Eranian 		inject.tool.finished_round = perf_event__drop_oe;
23939b07e27fSStephane Eranian 	}
23949b07e27fSStephane Eranian #endif
23959fedfb0cSTaeung Song 	ret = symbol__init(&inject.session->header.env);
23969fedfb0cSTaeung Song 	if (ret < 0)
23979fedfb0cSTaeung Song 		goto out_delete;
2398454c407eSTom Zanussi 
23991cb8bdccSNamhyung Kim 	ret = __cmd_inject(&inject);
24001cb8bdccSNamhyung Kim 
240197406a7eSAdrian Hunter 	guest_session__exit(&inject.guest_session);
240297406a7eSAdrian Hunter 
24039fedfb0cSTaeung Song out_delete:
24048012243eSRaul Silvera 	strlist__delete(inject.known_build_ids);
2405371a3378SAlexey Budankov 	zstd_fini(&(inject.session->zstd_data));
24061cb8bdccSNamhyung Kim 	perf_session__delete(inject.session);
240702e6246fSRiccardo Mancini out_close_output:
24080c8e32feSAdrian Hunter 	if (!inject.in_place_update)
240902e6246fSRiccardo Mancini 		perf_data__close(&inject.output);
241083d7f5f1SAdrian Hunter 	free(inject.itrace_synth_opts.vm_tm_corr_args);
2411d3944f0eSIan Rogers 	free(inject.event_copy);
2412*892d00fbSIan Rogers 	free(inject.guest_session.ev.event_buf);
24131cb8bdccSNamhyung Kim 	return ret;
2414454c407eSTom Zanussi }
2415