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"
21
#include "util/thread.h"
T
Tom Zanussi 已提交
22

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

143 144
	inject->have_auxtrace = true;

145 146 147 148 149 150 151 152 153 154 155 156
	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;
	}

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	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;
}

173 174 175 176 177 178 179 180 181 182 183 184 185
#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

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 228
	if (evsel->handler) {
		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_tool *tool,
					   union perf_event *event,
366
					   struct perf_session *session)
T
Tom Zanussi 已提交
367 368 369
{
	int err;

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

	return err;
}

376 377 378 379 380 381 382 383 384 385 386 387
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;
}

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

580
	evlist__for_each_entry(evlist, evsel)
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 607
		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;

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

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

	signal(SIGINT, sig_handler);

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

654 655
	output_data_offset = session->header.data_offset;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 874
	perf_session__delete(inject.session);
	return ret;
T
Tom Zanussi 已提交
875
}