builtin-inject.c 22.6 KB
Newer Older
T
Tom Zanussi 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * 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"
11 12 13
#include "util/color.h"
#include "util/evlist.h"
#include "util/evsel.h"
T
Tom Zanussi 已提交
14
#include "util/session.h"
15
#include "util/tool.h"
T
Tom Zanussi 已提交
16
#include "util/debug.h"
17
#include "util/build-id.h"
18
#include "util/data.h"
19
#include "util/auxtrace.h"
20
#include "util/jit.h"
T
Tom Zanussi 已提交
21

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

24
#include <linux/list.h>
25
#include <errno.h>
26
#include <signal.h>
27

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

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

50
static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
T
Tom Zanussi 已提交
51
{
52
	ssize_t size;
T
Tom Zanussi 已提交
53

54
	size = perf_data_file__write(&inject->output, buf, sz);
55 56
	if (size < 0)
		return -errno;
T
Tom Zanussi 已提交
57

58
	inject->bytes_written += size;
T
Tom Zanussi 已提交
59 60 61
	return 0;
}

62 63 64 65 66 67 68 69 70
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);
}

71 72 73 74 75 76 77
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);
}

78
#ifdef HAVE_JITDUMP
79 80 81 82 83 84 85 86
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

87
static int perf_event__repipe_op2_synth(struct perf_tool *tool,
88
					union perf_event *event,
89 90
					struct perf_session *session
					__maybe_unused)
91
{
92
	return perf_event__repipe_synth(tool, event);
93 94
}

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

	ret = perf_event__process_attr(tool, event, pevlist);
104 105 106
	if (ret)
		return ret;

107
	if (!inject->output.is_pipe)
108 109
		return 0;

110
	return perf_event__repipe_synth(tool, event);
111 112
}

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
#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;
}

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

142 143
	inject->have_auxtrace = true;

144 145 146 147 148 149 150 151 152 153 154 155
	if (!inject->output.is_pipe) {
		off_t offset;

		offset = lseek(inject->output.fd, 0, SEEK_CUR);
		if (offset == -1)
			return -errno;
		ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
						     event, offset);
		if (ret < 0)
			return ret;
	}

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

	return event->auxtrace.size;
}

172 173 174 175 176 177 178 179 180 181 182 183 184
#else

static s64
perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused,
			    union perf_event *event __maybe_unused,
			    struct perf_session *session __maybe_unused)
{
	pr_err("AUX area tracing not supported\n");
	return -EINVAL;
}

#endif

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

193 194 195 196 197 198 199 200
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;
}

201 202 203 204 205 206 207 208 209 210 211 212 213
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;
}

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

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

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

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

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

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

	return err;
}

249
#ifdef HAVE_JITDUMP
250 251 252 253 254 255 256
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;
257
	int ret;
258 259 260 261

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

274 275 276 277 278 279 280 281 282 283 284 285 286
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;
}

287
#ifdef HAVE_JITDUMP
288 289 290 291 292 293 294
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;
295
	int ret;
296 297 298 299

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

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

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

	return err;
}

325 326 327 328 329 330 331 332 333 334 335 336 337
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;
}

338 339 340 341 342 343 344 345 346 347 348 349
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;
}

350 351 352 353 354 355 356 357 358 359 360 361 362
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;
}

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

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

	return err;
}

375 376 377 378 379 380 381 382 383 384 385 386
static int perf_event__repipe_id_index(struct perf_tool *tool,
				       union perf_event *event,
				       struct perf_session *session)
{
	int err;

	perf_event__repipe_synth(tool, event);
	err = perf_event__process_id_index(tool, event, session);

	return err;
}

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

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

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

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

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

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

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

	return 0;
}

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

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

441
	thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
T
Tom Zanussi 已提交
442 443 444 445

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

462
	thread__put(thread);
T
Tom Zanussi 已提交
463
repipe:
464
	perf_event__repipe(tool, event, sample, machine);
465
	return 0;
T
Tom Zanussi 已提交
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 534 535 536
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,
537 538
				      evsel->attr.read_format, &sample_sw,
				      false);
539
	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
540 541 542
	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
}

543
static void sig_handler(int sig __maybe_unused)
T
Tom Zanussi 已提交
544 545 546 547
{
	session_done = 1;
}

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
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;
}

563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
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;

579
	evlist__for_each_entry(evlist, evsel)
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
		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;

607
	evlist__for_each_entry(evlist, evsel) {
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
		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 */
625
	evlist__for_each_entry_safe(evlist, tmp, evsel) {
626 627 628 629 630 631 632 633 634
		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);
		}
	}
}

635
static int __cmd_inject(struct perf_inject *inject)
T
Tom Zanussi 已提交
636 637
{
	int ret = -EINVAL;
638
	struct perf_session *session = inject->session;
639
	struct perf_data_file *file_out = &inject->output;
640
	int fd = perf_data_file__fd(file_out);
641
	u64 output_data_offset;
T
Tom Zanussi 已提交
642 643 644

	signal(SIGINT, sig_handler);

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

653 654
	output_data_offset = session->header.data_offset;

655 656 657
	if (inject->build_ids) {
		inject->tool.sample = perf_event__inject_buildid;
	} else if (inject->sched_stat) {
658 659
		struct perf_evsel *evsel;

660
		evlist__for_each_entry(session->evlist, evsel) {
661 662 663 664 665 666
			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;

667
				evsel->handler = perf_inject__sched_switch;
668
			} else if (!strcmp(name, "sched:sched_process_exit"))
669
				evsel->handler = perf_inject__sched_process_exit;
670
			else if (!strncmp(name, "sched:sched_stat_", 17))
671
				evsel->handler = perf_inject__sched_stat;
672
		}
673 674 675 676
	} 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;
677
		inject->tool.namespaces	    = perf_event__repipe_namespaces;
678 679 680 681
		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;
682 683
		inject->tool.aux	    = perf_event__drop_aux;
		inject->tool.itrace_start   = perf_event__drop_aux,
684 685 686 687
		inject->tool.ordered_events = true;
		inject->tool.ordering_requires_timestamps = true;
		/* Allow space in the header for new attributes */
		output_data_offset = 4096;
688 689
		if (inject->strip)
			strip_init(inject);
690 691
	}

692 693 694
	if (!inject->itrace_synth_opts.set)
		auxtrace_index__free(&session->auxtrace_index);

695
	if (!file_out->is_pipe)
696
		lseek(fd, output_data_offset, SEEK_SET);
A
Andrew Vagin 已提交
697

698
	ret = perf_session__process_events(session);
699 700
	if (ret)
		return ret;
T
Tom Zanussi 已提交
701

702
	if (!file_out->is_pipe) {
703
		if (inject->build_ids)
704 705
			perf_header__set_feat(&session->header,
					      HEADER_BUILD_ID);
706 707 708 709 710 711 712
		/*
		 * 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);
713 714
		/*
		 * The AUX areas have been removed and replaced with
715 716
		 * synthesized hardware events, so clear the feature flag and
		 * remove the evsel.
717
		 */
718
		if (inject->itrace_synth_opts.set) {
719 720
			struct perf_evsel *evsel;

721 722
			perf_header__clear_feat(&session->header,
						HEADER_AUXTRACE);
723 724 725
			if (inject->itrace_synth_opts.last_branch)
				perf_header__set_feat(&session->header,
						      HEADER_BRANCH_STACK);
726 727 728 729 730 731 732 733
			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);
			}
734 735
			if (inject->strip)
				strip_fini(inject);
736
		}
737
		session->header.data_offset = output_data_offset;
A
Andrew Vagin 已提交
738
		session->header.data_size = inject->bytes_written;
739
		perf_session__write_header(session, session->evlist, fd, true);
A
Andrew Vagin 已提交
740 741
	}

T
Tom Zanussi 已提交
742 743 744
	return ret;
}

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

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

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

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

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

835 836
	inject.tool.ordered_events = inject.sched_stat;

837 838 839
	file.path = inject.input_name;
	inject.session = perf_session__new(&file, true, &inject.tool);
	if (inject.session == NULL)
840
		return -1;
841

842 843 844 845 846 847 848 849 850 851
	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;
	}
852
#ifdef HAVE_JITDUMP
853 854 855 856 857 858 859 860 861 862 863 864
	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
865 866 867
	ret = symbol__init(&inject.session->header.env);
	if (ret < 0)
		goto out_delete;
T
Tom Zanussi 已提交
868

869 870
	ret = __cmd_inject(&inject);

871
out_delete:
872 873
	perf_session__delete(inject.session);
	return ret;
T
Tom Zanussi 已提交
874
}