builtin-inject.c 22.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
T
Tom Zanussi 已提交
2 3 4 5 6 7 8 9 10 11
/*
 * builtin-inject.c
 *
 * Builtin inject command: Examine the live mode (stdin) event stream
 * and repipe it to stdout while optionally injecting additional
 * events into it.
 */
#include "builtin.h"

#include "perf.h"
12 13 14
#include "util/color.h"
#include "util/evlist.h"
#include "util/evsel.h"
15
#include "util/map.h"
T
Tom Zanussi 已提交
16
#include "util/session.h"
17
#include "util/tool.h"
T
Tom Zanussi 已提交
18
#include "util/debug.h"
19
#include "util/build-id.h"
20
#include "util/data.h"
21
#include "util/auxtrace.h"
22
#include "util/jit.h"
23
#include "util/symbol.h"
24
#include "util/thread.h"
T
Tom Zanussi 已提交
25

26
#include <subcmd/parse-options.h>
T
Tom Zanussi 已提交
27

28
#include <linux/list.h>
29
#include <errno.h>
30
#include <signal.h>
31

32
struct perf_inject {
33
	struct perf_tool	tool;
34
	struct perf_session	*session;
35 36
	bool			build_ids;
	bool			sched_stat;
37
	bool			have_auxtrace;
38
	bool			strip;
39
	bool			jit_mode;
40
	const char		*input_name;
41
	struct perf_data	output;
42
	u64			bytes_written;
43
	u64			aux_id;
44
	struct list_head	samples;
45
	struct itrace_synth_opts itrace_synth_opts;
46 47 48 49 50 51
};

struct event_entry {
	struct list_head node;
	u32		 tid;
	union perf_event event[0];
52
};
T
Tom Zanussi 已提交
53

54
static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
T
Tom Zanussi 已提交
55
{
56
	ssize_t size;
T
Tom Zanussi 已提交
57

58
	size = perf_data__write(&inject->output, buf, sz);
59 60
	if (size < 0)
		return -errno;
T
Tom Zanussi 已提交
61

62
	inject->bytes_written += size;
T
Tom Zanussi 已提交
63 64 65
	return 0;
}

66 67 68 69 70 71 72 73 74
static int perf_event__repipe_synth(struct perf_tool *tool,
				    union perf_event *event)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject,
						  tool);

	return output_bytes(inject, event, event->header.size);
}

75 76 77 78 79 80 81
static int perf_event__repipe_oe_synth(struct perf_tool *tool,
				       union perf_event *event,
				       struct ordered_events *oe __maybe_unused)
{
	return perf_event__repipe_synth(tool, event);
}

82
#ifdef HAVE_JITDUMP
83 84 85 86 87 88 89 90
static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
			       union perf_event *event __maybe_unused,
			       struct ordered_events *oe __maybe_unused)
{
	return 0;
}
#endif

91 92
static int perf_event__repipe_op2_synth(struct perf_session *session,
					union perf_event *event)
93
{
94
	return perf_event__repipe_synth(session->tool, event);
95 96
}

97 98 99
static int perf_event__repipe_attr(struct perf_tool *tool,
				   union perf_event *event,
				   struct perf_evlist **pevlist)
100
{
101 102
	struct perf_inject *inject = container_of(tool, struct perf_inject,
						  tool);
103
	int ret;
104 105

	ret = perf_event__process_attr(tool, event, pevlist);
106 107 108
	if (ret)
		return ret;

109
	if (!inject->output.is_pipe)
110 111
		return 0;

112
	return perf_event__repipe_synth(tool, event);
113 114
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
#ifdef HAVE_AUXTRACE_SUPPORT

static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
{
	char buf[4096];
	ssize_t ssz;
	int ret;

	while (size > 0) {
		ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
		if (ssz < 0)
			return -errno;
		ret = output_bytes(inject, buf, ssz);
		if (ret)
			return ret;
		size -= ssz;
	}

	return 0;
}

136 137
static s64 perf_event__repipe_auxtrace(struct perf_session *session,
				       union perf_event *event)
138
{
139
	struct perf_tool *tool = session->tool;
140 141 142 143
	struct perf_inject *inject = container_of(tool, struct perf_inject,
						  tool);
	int ret;

144 145
	inject->have_auxtrace = true;

146 147 148
	if (!inject->output.is_pipe) {
		off_t offset;

J
Jiri Olsa 已提交
149
		offset = lseek(inject->output.file.fd, 0, SEEK_CUR);
150 151 152 153 154 155 156 157
		if (offset == -1)
			return -errno;
		ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
						     event, offset);
		if (ret < 0)
			return ret;
	}

158
	if (perf_data__is_pipe(session->data) || !session->one_mmap) {
159 160 161
		ret = output_bytes(inject, event, event->header.size);
		if (ret < 0)
			return ret;
162
		ret = copy_bytes(inject, perf_data__fd(session->data),
163 164 165 166 167 168 169 170 171 172 173
				 event->auxtrace.size);
	} else {
		ret = output_bytes(inject, event,
				   event->header.size + event->auxtrace.size);
	}
	if (ret < 0)
		return ret;

	return event->auxtrace.size;
}

174 175 176
#else

static s64
177 178
perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused,
			    union perf_event *event __maybe_unused)
179 180 181 182 183 184 185
{
	pr_err("AUX area tracing not supported\n");
	return -EINVAL;
}

#endif

186
static int perf_event__repipe(struct perf_tool *tool,
187
			      union perf_event *event,
188
			      struct perf_sample *sample __maybe_unused,
189
			      struct machine *machine __maybe_unused)
190
{
191
	return perf_event__repipe_synth(tool, event);
192 193
}

194 195 196 197 198 199 200 201
static int 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)
{
	return 0;
}

202 203 204 205 206 207 208 209 210 211 212 213 214
static int perf_event__drop_aux(struct perf_tool *tool,
				union perf_event *event __maybe_unused,
				struct perf_sample *sample,
				struct machine *machine __maybe_unused)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);

	if (!inject->aux_id)
		inject->aux_id = sample->id;

	return 0;
}

215 216 217 218 219 220
typedef int (*inject_handler)(struct perf_tool *tool,
			      union perf_event *event,
			      struct perf_sample *sample,
			      struct perf_evsel *evsel,
			      struct machine *machine);

221
static int perf_event__repipe_sample(struct perf_tool *tool,
222
				     union perf_event *event,
223 224 225
				     struct perf_sample *sample,
				     struct perf_evsel *evsel,
				     struct machine *machine)
226
{
227
	if (evsel && evsel->handler) {
228
		inject_handler f = evsel->handler;
229 230 231
		return f(tool, event, sample, evsel, machine);
	}

232 233
	build_id__mark_dso_hit(tool, event, sample, evsel, machine);

234
	return perf_event__repipe_synth(tool, event);
235 236
}

237
static int perf_event__repipe_mmap(struct perf_tool *tool,
238
				   union perf_event *event,
239
				   struct perf_sample *sample,
240
				   struct machine *machine)
T
Tom Zanussi 已提交
241 242 243
{
	int err;

244 245
	err = perf_event__process_mmap(tool, event, sample, machine);
	perf_event__repipe(tool, event, sample, machine);
T
Tom Zanussi 已提交
246 247 248 249

	return err;
}

250
#ifdef HAVE_JITDUMP
251 252 253 254 255 256 257
static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
				       union perf_event *event,
				       struct perf_sample *sample,
				       struct machine *machine)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	u64 n = 0;
258
	int ret;
259 260 261 262

	/*
	 * if jit marker, then inject jit mmaps and generate ELF images
	 */
263 264 265 266 267
	ret = jit_process(inject->session, &inject->output, machine,
			  event->mmap.filename, sample->pid, &n);
	if (ret < 0)
		return ret;
	if (ret) {
268 269 270 271 272 273 274
		inject->bytes_written += n;
		return 0;
	}
	return perf_event__repipe_mmap(tool, event, sample, machine);
}
#endif

275 276 277 278 279 280 281 282 283 284 285 286 287
static int perf_event__repipe_mmap2(struct perf_tool *tool,
				   union perf_event *event,
				   struct perf_sample *sample,
				   struct machine *machine)
{
	int err;

	err = perf_event__process_mmap2(tool, event, sample, machine);
	perf_event__repipe(tool, event, sample, machine);

	return err;
}

288
#ifdef HAVE_JITDUMP
289 290 291 292 293 294 295
static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
					union perf_event *event,
					struct perf_sample *sample,
					struct machine *machine)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	u64 n = 0;
296
	int ret;
297 298 299 300

	/*
	 * if jit marker, then inject jit mmaps and generate ELF images
	 */
301 302 303 304 305
	ret = jit_process(inject->session, &inject->output, machine,
			  event->mmap2.filename, sample->pid, &n);
	if (ret < 0)
		return ret;
	if (ret) {
306 307 308 309 310 311 312
		inject->bytes_written += n;
		return 0;
	}
	return perf_event__repipe_mmap2(tool, event, sample, machine);
}
#endif

313
static int perf_event__repipe_fork(struct perf_tool *tool,
314
				   union perf_event *event,
315
				   struct perf_sample *sample,
316
				   struct machine *machine)
T
Tom Zanussi 已提交
317 318 319
{
	int err;

320
	err = perf_event__process_fork(tool, event, sample, machine);
321
	perf_event__repipe(tool, event, sample, machine);
T
Tom Zanussi 已提交
322 323 324 325

	return err;
}

326 327 328 329 330 331 332 333 334 335 336 337 338
static int perf_event__repipe_comm(struct perf_tool *tool,
				   union perf_event *event,
				   struct perf_sample *sample,
				   struct machine *machine)
{
	int err;

	err = perf_event__process_comm(tool, event, sample, machine);
	perf_event__repipe(tool, event, sample, machine);

	return err;
}

339 340 341 342 343 344 345 346 347 348 349 350
static int perf_event__repipe_namespaces(struct perf_tool *tool,
					 union perf_event *event,
					 struct perf_sample *sample,
					 struct machine *machine)
{
	int err = perf_event__process_namespaces(tool, event, sample, machine);

	perf_event__repipe(tool, event, sample, machine);

	return err;
}

351 352 353 354 355 356 357 358 359 360 361 362 363
static int perf_event__repipe_exit(struct perf_tool *tool,
				   union perf_event *event,
				   struct perf_sample *sample,
				   struct machine *machine)
{
	int err;

	err = perf_event__process_exit(tool, event, sample, machine);
	perf_event__repipe(tool, event, sample, machine);

	return err;
}

364 365
static int perf_event__repipe_tracing_data(struct perf_session *session,
					   union perf_event *event)
T
Tom Zanussi 已提交
366 367 368
{
	int err;

369 370
	perf_event__repipe_synth(session->tool, event);
	err = perf_event__process_tracing_data(session, event);
T
Tom Zanussi 已提交
371 372 373 374

	return err;
}

375 376
static int perf_event__repipe_id_index(struct perf_session *session,
				       union perf_event *event)
377 378 379
{
	int err;

380 381
	perf_event__repipe_synth(session->tool, event);
	err = perf_event__process_id_index(session, event);
382 383 384 385

	return err;
}

386
static int dso__read_build_id(struct dso *dso)
T
Tom Zanussi 已提交
387
{
388
	if (dso->has_build_id)
389
		return 0;
T
Tom Zanussi 已提交
390

391 392 393
	if (filename__read_build_id(dso->long_name, dso->build_id,
				    sizeof(dso->build_id)) > 0) {
		dso->has_build_id = true;
394 395
		return 0;
	}
T
Tom Zanussi 已提交
396

397 398
	return -1;
}
T
Tom Zanussi 已提交
399

400
static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
401
				struct machine *machine)
402 403 404
{
	u16 misc = PERF_RECORD_MISC_USER;
	int err;
T
Tom Zanussi 已提交
405

406 407
	if (dso__read_build_id(dso) < 0) {
		pr_debug("no build_id found for %s\n", dso->long_name);
408 409
		return -1;
	}
T
Tom Zanussi 已提交
410

411
	if (dso->kernel)
412
		misc = PERF_RECORD_MISC_KERNEL;
T
Tom Zanussi 已提交
413

414
	err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
415
					      machine);
416
	if (err) {
417
		pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
T
Tom Zanussi 已提交
418 419 420 421 422 423
		return -1;
	}

	return 0;
}

424
static int perf_event__inject_buildid(struct perf_tool *tool,
425
				      union perf_event *event,
426
				      struct perf_sample *sample,
427
				      struct perf_evsel *evsel __maybe_unused,
428
				      struct machine *machine)
T
Tom Zanussi 已提交
429 430 431 432
{
	struct addr_location al;
	struct thread *thread;

433
	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
T
Tom Zanussi 已提交
434 435 436 437 438 439
	if (thread == NULL) {
		pr_err("problem processing %d event, skipping it.\n",
		       event->header.type);
		goto repipe;
	}

440
	if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {
T
Tom Zanussi 已提交
441 442
		if (!al.map->dso->hit) {
			al.map->dso->hit = 1;
443
			if (map__load(al.map) >= 0) {
444
				dso__inject_build_id(al.map->dso, tool, machine);
445 446 447 448
				/*
				 * If this fails, too bad, let the other side
				 * account this as unresolved.
				 */
449
			} else {
450
#ifdef HAVE_LIBELF_SUPPORT
T
Tom Zanussi 已提交
451 452 453
				pr_warning("no symbols found in %s, maybe "
					   "install a debug package?\n",
					   al.map->dso->long_name);
454 455
#endif
			}
T
Tom Zanussi 已提交
456 457 458
		}
	}

459
	thread__put(thread);
T
Tom Zanussi 已提交
460
repipe:
461
	perf_event__repipe(tool, event, sample, machine);
462
	return 0;
T
Tom Zanussi 已提交
463 464
}

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
static int perf_inject__sched_process_exit(struct perf_tool *tool,
					   union perf_event *event __maybe_unused,
					   struct perf_sample *sample,
					   struct perf_evsel *evsel __maybe_unused,
					   struct machine *machine __maybe_unused)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	struct event_entry *ent;

	list_for_each_entry(ent, &inject->samples, node) {
		if (sample->tid == ent->tid) {
			list_del_init(&ent->node);
			free(ent);
			break;
		}
	}

	return 0;
}

static int perf_inject__sched_switch(struct perf_tool *tool,
				     union perf_event *event,
				     struct perf_sample *sample,
				     struct perf_evsel *evsel,
				     struct machine *machine)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	struct event_entry *ent;

	perf_inject__sched_process_exit(tool, event, sample, evsel, machine);

	ent = malloc(event->header.size + sizeof(struct event_entry));
	if (ent == NULL) {
		color_fprintf(stderr, PERF_COLOR_RED,
			     "Not enough memory to process sched switch event!");
		return -1;
	}

	ent->tid = sample->tid;
	memcpy(&ent->event, event, event->header.size);
	list_add(&ent->node, &inject->samples);
	return 0;
}

static int perf_inject__sched_stat(struct perf_tool *tool,
				   union perf_event *event __maybe_unused,
				   struct perf_sample *sample,
				   struct perf_evsel *evsel,
				   struct machine *machine)
{
	struct event_entry *ent;
	union perf_event *event_sw;
	struct perf_sample sample_sw;
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	u32 pid = perf_evsel__intval(evsel, sample, "pid");

	list_for_each_entry(ent, &inject->samples, node) {
		if (pid == ent->tid)
			goto found;
	}

	return 0;
found:
	event_sw = &ent->event[0];
	perf_evsel__parse_sample(evsel, event_sw, &sample_sw);

	sample_sw.period = sample->period;
	sample_sw.time	 = sample->time;
	perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
534
				      evsel->attr.read_format, &sample_sw);
535
	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
536 537 538
	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
}

539
static void sig_handler(int sig __maybe_unused)
T
Tom Zanussi 已提交
540 541 542 543
{
	session_done = 1;
}

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
static int perf_evsel__check_stype(struct perf_evsel *evsel,
				   u64 sample_type, const char *sample_msg)
{
	struct perf_event_attr *attr = &evsel->attr;
	const char *name = perf_evsel__name(evsel);

	if (!(attr->sample_type & sample_type)) {
		pr_err("Samples for %s event do not have %s attribute set.",
			name, sample_msg);
		return -EINVAL;
	}

	return 0;
}

559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
static int drop_sample(struct perf_tool *tool __maybe_unused,
		       union perf_event *event __maybe_unused,
		       struct perf_sample *sample __maybe_unused,
		       struct perf_evsel *evsel __maybe_unused,
		       struct machine *machine __maybe_unused)
{
	return 0;
}

static void strip_init(struct perf_inject *inject)
{
	struct perf_evlist *evlist = inject->session->evlist;
	struct perf_evsel *evsel;

	inject->tool.context_switch = perf_event__drop;

575
	evlist__for_each_entry(evlist, evsel)
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
		evsel->handler = drop_sample;
}

static bool has_tracking(struct perf_evsel *evsel)
{
	return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm ||
	       evsel->attr.task;
}

#define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \
		     PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER)

/*
 * In order that the perf.data file is parsable, tracking events like MMAP need
 * their selected event to exist, except if there is only 1 selected event left
 * and it has a compatible sample type.
 */
static bool ok_to_remove(struct perf_evlist *evlist,
			 struct perf_evsel *evsel_to_remove)
{
	struct perf_evsel *evsel;
	int cnt = 0;
	bool ok = false;

	if (!has_tracking(evsel_to_remove))
		return true;

603
	evlist__for_each_entry(evlist, evsel) {
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
		if (evsel->handler != drop_sample) {
			cnt += 1;
			if ((evsel->attr.sample_type & COMPAT_MASK) ==
			    (evsel_to_remove->attr.sample_type & COMPAT_MASK))
				ok = true;
		}
	}

	return ok && cnt == 1;
}

static void strip_fini(struct perf_inject *inject)
{
	struct perf_evlist *evlist = inject->session->evlist;
	struct perf_evsel *evsel, *tmp;

	/* Remove non-synthesized evsels if possible */
621
	evlist__for_each_entry_safe(evlist, tmp, evsel) {
622 623 624 625 626 627 628 629 630
		if (evsel->handler == drop_sample &&
		    ok_to_remove(evlist, evsel)) {
			pr_debug("Deleting %s\n", perf_evsel__name(evsel));
			perf_evlist__remove(evlist, evsel);
			perf_evsel__delete(evsel);
		}
	}
}

631
static int __cmd_inject(struct perf_inject *inject)
T
Tom Zanussi 已提交
632 633
{
	int ret = -EINVAL;
634
	struct perf_session *session = inject->session;
635 636
	struct perf_data *data_out = &inject->output;
	int fd = perf_data__fd(data_out);
637
	u64 output_data_offset;
T
Tom Zanussi 已提交
638 639 640

	signal(SIGINT, sig_handler);

641 642
	if (inject->build_ids || inject->sched_stat ||
	    inject->itrace_synth_opts.set) {
643
		inject->tool.mmap	  = perf_event__repipe_mmap;
644
		inject->tool.mmap2	  = perf_event__repipe_mmap2;
645
		inject->tool.fork	  = perf_event__repipe_fork;
646
		inject->tool.tracing_data = perf_event__repipe_tracing_data;
T
Tom Zanussi 已提交
647 648
	}

649 650
	output_data_offset = session->header.data_offset;

651 652 653
	if (inject->build_ids) {
		inject->tool.sample = perf_event__inject_buildid;
	} else if (inject->sched_stat) {
654 655
		struct perf_evsel *evsel;

656
		evlist__for_each_entry(session->evlist, evsel) {
657 658 659 660 661 662
			const char *name = perf_evsel__name(evsel);

			if (!strcmp(name, "sched:sched_switch")) {
				if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
					return -EINVAL;

663
				evsel->handler = perf_inject__sched_switch;
664
			} else if (!strcmp(name, "sched:sched_process_exit"))
665
				evsel->handler = perf_inject__sched_process_exit;
666
			else if (!strncmp(name, "sched:sched_stat_", 17))
667
				evsel->handler = perf_inject__sched_stat;
668
		}
669 670 671 672
	} else if (inject->itrace_synth_opts.set) {
		session->itrace_synth_opts = &inject->itrace_synth_opts;
		inject->itrace_synth_opts.inject = true;
		inject->tool.comm	    = perf_event__repipe_comm;
673
		inject->tool.namespaces	    = perf_event__repipe_namespaces;
674 675 676 677
		inject->tool.exit	    = perf_event__repipe_exit;
		inject->tool.id_index	    = perf_event__repipe_id_index;
		inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
		inject->tool.auxtrace	    = perf_event__process_auxtrace;
678 679
		inject->tool.aux	    = perf_event__drop_aux;
		inject->tool.itrace_start   = perf_event__drop_aux,
680 681 682 683
		inject->tool.ordered_events = true;
		inject->tool.ordering_requires_timestamps = true;
		/* Allow space in the header for new attributes */
		output_data_offset = 4096;
684 685
		if (inject->strip)
			strip_init(inject);
686 687
	}

688 689 690
	if (!inject->itrace_synth_opts.set)
		auxtrace_index__free(&session->auxtrace_index);

691
	if (!data_out->is_pipe)
692
		lseek(fd, output_data_offset, SEEK_SET);
A
Andrew Vagin 已提交
693

694
	ret = perf_session__process_events(session);
695 696
	if (ret)
		return ret;
T
Tom Zanussi 已提交
697

698
	if (!data_out->is_pipe) {
699
		if (inject->build_ids)
700 701
			perf_header__set_feat(&session->header,
					      HEADER_BUILD_ID);
702 703 704 705 706 707 708
		/*
		 * Keep all buildids when there is unprocessed AUX data because
		 * it is not known which ones the AUX trace hits.
		 */
		if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
		    inject->have_auxtrace && !inject->itrace_synth_opts.set)
			dsos__hit_all(session);
709 710
		/*
		 * The AUX areas have been removed and replaced with
711 712
		 * synthesized hardware events, so clear the feature flag and
		 * remove the evsel.
713
		 */
714
		if (inject->itrace_synth_opts.set) {
715 716
			struct perf_evsel *evsel;

717 718
			perf_header__clear_feat(&session->header,
						HEADER_AUXTRACE);
719 720 721
			if (inject->itrace_synth_opts.last_branch)
				perf_header__set_feat(&session->header,
						      HEADER_BRANCH_STACK);
722 723 724 725 726 727 728 729
			evsel = perf_evlist__id2evsel_strict(session->evlist,
							     inject->aux_id);
			if (evsel) {
				pr_debug("Deleting %s\n",
					 perf_evsel__name(evsel));
				perf_evlist__remove(session->evlist, evsel);
				perf_evsel__delete(evsel);
			}
730 731
			if (inject->strip)
				strip_fini(inject);
732
		}
733
		session->header.data_offset = output_data_offset;
A
Andrew Vagin 已提交
734
		session->header.data_size = inject->bytes_written;
735
		perf_session__write_header(session, session->evlist, fd, true);
A
Andrew Vagin 已提交
736 737
	}

T
Tom Zanussi 已提交
738 739 740
	return ret;
}

741
int cmd_inject(int argc, const char **argv)
T
Tom Zanussi 已提交
742
{
743 744 745 746
	struct perf_inject inject = {
		.tool = {
			.sample		= perf_event__repipe_sample,
			.mmap		= perf_event__repipe,
747
			.mmap2		= perf_event__repipe,
748 749 750 751
			.comm		= perf_event__repipe,
			.fork		= perf_event__repipe,
			.exit		= perf_event__repipe,
			.lost		= perf_event__repipe,
752
			.lost_samples	= perf_event__repipe,
753
			.aux		= perf_event__repipe,
754
			.itrace_start	= perf_event__repipe,
755
			.context_switch	= perf_event__repipe,
756 757 758 759
			.read		= perf_event__repipe_sample,
			.throttle	= perf_event__repipe,
			.unthrottle	= perf_event__repipe,
			.attr		= perf_event__repipe_attr,
760
			.tracing_data	= perf_event__repipe_op2_synth,
761 762 763
			.auxtrace_info	= perf_event__repipe_op2_synth,
			.auxtrace	= perf_event__repipe_auxtrace,
			.auxtrace_error	= perf_event__repipe_op2_synth,
764
			.time_conv	= perf_event__repipe_op2_synth,
765
			.finished_round	= perf_event__repipe_oe_synth,
766
			.build_id	= perf_event__repipe_op2_synth,
A
Adrian Hunter 已提交
767
			.id_index	= perf_event__repipe_op2_synth,
768
			.feature	= perf_event__repipe_op2_synth,
769
		},
A
Andrew Vagin 已提交
770
		.input_name  = "-",
771
		.samples = LIST_HEAD_INIT(inject.samples),
772
		.output = {
J
Jiri Olsa 已提交
773 774
			.path = "-",
			.mode = PERF_DATA_MODE_WRITE,
775
		},
776
	};
777
	struct perf_data data = {
778 779 780 781
		.mode = PERF_DATA_MODE_READ,
	};
	int ret;

782
	struct option options[] = {
783 784
		OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
			    "Inject build-ids into the output stream"),
A
Andrew Vagin 已提交
785 786
		OPT_STRING('i', "input", &inject.input_name, "file",
			   "input file name"),
J
Jiri Olsa 已提交
787
		OPT_STRING('o', "output", &inject.output.path, "file",
A
Andrew Vagin 已提交
788
			   "output file name"),
789 790 791
		OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
			    "Merge sched-stat and sched-switch for getting events "
			    "where and how long tasks slept"),
792
#ifdef HAVE_JITDUMP
793
		OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
794
#endif
795 796
		OPT_INCR('v', "verbose", &verbose,
			 "be more verbose (show build ids, etc)"),
797 798
		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
			   "kallsyms pathname"),
799
		OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
800
		OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
801 802
				    NULL, "opts", "Instruction Tracing options\n"
				    ITRACE_HELP,
803
				    itrace_parse_synth_opts),
804 805
		OPT_BOOLEAN(0, "strip", &inject.strip,
			    "strip non-synthesized events (use with --itrace)"),
806 807
		OPT_END()
	};
808 809 810 811
	const char * const inject_usage[] = {
		"perf inject [<options>]",
		NULL
	};
812
#ifndef HAVE_JITDUMP
813 814
	set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
#endif
815
	argc = parse_options(argc, argv, options, inject_usage, 0);
T
Tom Zanussi 已提交
816 817 818 819 820

	/*
	 * Any (unrecognized) arguments left?
	 */
	if (argc)
821
		usage_with_options(inject_usage, options);
T
Tom Zanussi 已提交
822

823 824 825 826 827
	if (inject.strip && !inject.itrace_synth_opts.set) {
		pr_err("--strip option requires --itrace option\n");
		return -1;
	}

828
	if (perf_data__open(&inject.output)) {
829 830
		perror("failed to create output file");
		return -1;
A
Andrew Vagin 已提交
831 832
	}

833 834
	inject.tool.ordered_events = inject.sched_stat;

J
Jiri Olsa 已提交
835
	data.path = inject.input_name;
836
	inject.session = perf_session__new(&data, true, &inject.tool);
837
	if (inject.session == NULL)
838
		return -1;
839

840 841 842
	if (zstd_init(&(inject.session->zstd_data), 0) < 0)
		pr_warning("Decompression initialization failed.\n");

843 844 845 846 847 848 849 850 851 852
	if (inject.build_ids) {
		/*
		 * to make sure the mmap records are ordered correctly
		 * and so that the correct especially due to jitted code
		 * mmaps. We cannot generate the buildid hit list and
		 * inject the jit mmaps at the same time for now.
		 */
		inject.tool.ordered_events = true;
		inject.tool.ordering_requires_timestamps = true;
	}
853
#ifdef HAVE_JITDUMP
854 855 856 857 858 859 860 861 862 863 864 865
	if (inject.jit_mode) {
		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
		inject.tool.ordered_events = true;
		inject.tool.ordering_requires_timestamps = true;
		/*
		 * JIT MMAP injection injects all MMAP events in one go, so it
		 * does not obey finished_round semantics.
		 */
		inject.tool.finished_round = perf_event__drop_oe;
	}
#endif
866 867 868
	ret = symbol__init(&inject.session->header.env);
	if (ret < 0)
		goto out_delete;
T
Tom Zanussi 已提交
869

870 871
	ret = __cmd_inject(&inject);

872
out_delete:
873
	zstd_fini(&(inject.session->zstd_data));
874 875
	perf_session__delete(inject.session);
	return ret;
T
Tom Zanussi 已提交
876
}