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