builtin-inject.c 22.7 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 25
#include <linux/list.h>

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

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

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

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

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

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

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

76 77 78 79 80 81 82 83 84
#ifdef HAVE_LIBELF_SUPPORT
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

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

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

	ret = perf_event__process_attr(tool, event, pevlist);
102 103 104
	if (ret)
		return ret;

105
	if (!inject->output.is_pipe)
106 107
		return 0;

108
	return perf_event__repipe_synth(tool, event);
109 110
}

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

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

141 142
	inject->have_auxtrace = true;

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

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

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

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

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

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

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

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

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

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

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

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

	return err;
}

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
#ifdef HAVE_LIBELF_SUPPORT
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;

	/*
	 * if jit marker, then inject jit mmaps and generate ELF images
	 */
	if (!jit_process(inject->session, &inject->output, machine,
			 event->mmap.filename, sample->pid, &n)) {
		inject->bytes_written += n;
		return 0;
	}
	return perf_event__repipe_mmap(tool, event, sample, machine);
}
#endif

269 270 271 272 273 274 275 276 277 278 279 280 281
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;
}

282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
#ifdef HAVE_LIBELF_SUPPORT
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;

	/*
	 * if jit marker, then inject jit mmaps and generate ELF images
	 */
	if (!jit_process(inject->session, &inject->output, machine,
			  event->mmap2.filename, sample->pid, &n)) {
		inject->bytes_written += n;
		return 0;
	}
	return perf_event__repipe_mmap2(tool, event, sample, machine);
}
#endif

303
static int perf_event__repipe_fork(struct perf_tool *tool,
304
				   union perf_event *event,
305
				   struct perf_sample *sample,
306
				   struct machine *machine)
T
Tom Zanussi 已提交
307 308 309
{
	int err;

310
	err = perf_event__process_fork(tool, event, sample, machine);
311
	perf_event__repipe(tool, event, sample, machine);
T
Tom Zanussi 已提交
312 313 314 315

	return err;
}

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
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;
}

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;
}

342 343
static int perf_event__repipe_tracing_data(struct perf_tool *tool,
					   union perf_event *event,
344
					   struct perf_session *session)
T
Tom Zanussi 已提交
345 346 347
{
	int err;

348 349
	perf_event__repipe_synth(tool, event);
	err = perf_event__process_tracing_data(tool, event, session);
T
Tom Zanussi 已提交
350 351 352 353

	return err;
}

354 355 356 357 358 359 360 361 362 363 364 365
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;
}

366
static int dso__read_build_id(struct dso *dso)
T
Tom Zanussi 已提交
367
{
368
	if (dso->has_build_id)
369
		return 0;
T
Tom Zanussi 已提交
370

371 372 373
	if (filename__read_build_id(dso->long_name, dso->build_id,
				    sizeof(dso->build_id)) > 0) {
		dso->has_build_id = true;
374 375
		return 0;
	}
T
Tom Zanussi 已提交
376

377 378
	return -1;
}
T
Tom Zanussi 已提交
379

380
static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
381
				struct machine *machine)
382 383 384
{
	u16 misc = PERF_RECORD_MISC_USER;
	int err;
T
Tom Zanussi 已提交
385

386 387
	if (dso__read_build_id(dso) < 0) {
		pr_debug("no build_id found for %s\n", dso->long_name);
388 389
		return -1;
	}
T
Tom Zanussi 已提交
390

391
	if (dso->kernel)
392
		misc = PERF_RECORD_MISC_KERNEL;
T
Tom Zanussi 已提交
393

394
	err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
395
					      machine);
396
	if (err) {
397
		pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
T
Tom Zanussi 已提交
398 399 400 401 402 403
		return -1;
	}

	return 0;
}

404
static int perf_event__inject_buildid(struct perf_tool *tool,
405
				      union perf_event *event,
406
				      struct perf_sample *sample,
407
				      struct perf_evsel *evsel __maybe_unused,
408
				      struct machine *machine)
T
Tom Zanussi 已提交
409 410 411 412 413 414 415
{
	struct addr_location al;
	struct thread *thread;
	u8 cpumode;

	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;

416
	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
T
Tom Zanussi 已提交
417 418 419 420 421 422
	if (thread == NULL) {
		pr_err("problem processing %d event, skipping it.\n",
		       event->header.type);
		goto repipe;
	}

423
	thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
T
Tom Zanussi 已提交
424 425 426 427

	if (al.map != NULL) {
		if (!al.map->dso->hit) {
			al.map->dso->hit = 1;
428
			if (map__load(al.map, NULL) >= 0) {
429
				dso__inject_build_id(al.map->dso, tool, machine);
430 431 432 433
				/*
				 * If this fails, too bad, let the other side
				 * account this as unresolved.
				 */
434
			} else {
435
#ifdef HAVE_LIBELF_SUPPORT
T
Tom Zanussi 已提交
436 437 438
				pr_warning("no symbols found in %s, maybe "
					   "install a debug package?\n",
					   al.map->dso->long_name);
439 440
#endif
			}
T
Tom Zanussi 已提交
441 442 443
		}
	}

444
	thread__put(thread);
T
Tom Zanussi 已提交
445
repipe:
446
	perf_event__repipe(tool, event, sample, machine);
447
	return 0;
T
Tom Zanussi 已提交
448 449
}

450 451 452 453 454 455 456 457 458 459 460 461 462 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
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,
519 520
				      evsel->attr.read_format, &sample_sw,
				      false);
521
	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
522 523 524
	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
}

525
static void sig_handler(int sig __maybe_unused)
T
Tom Zanussi 已提交
526 527 528 529
{
	session_done = 1;
}

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
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;
}

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 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 603 604 605 606 607 608 609 610 611 612 613 614 615 616
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;

	evlist__for_each(evlist, evsel)
		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;

	evlist__for_each(evlist, evsel) {
		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 */
	evlist__for_each_safe(evlist, tmp, evsel) {
		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);
		}
	}
}

617
static int __cmd_inject(struct perf_inject *inject)
T
Tom Zanussi 已提交
618 619
{
	int ret = -EINVAL;
620
	struct perf_session *session = inject->session;
621
	struct perf_data_file *file_out = &inject->output;
622
	int fd = perf_data_file__fd(file_out);
623
	u64 output_data_offset;
T
Tom Zanussi 已提交
624 625 626

	signal(SIGINT, sig_handler);

627 628
	if (inject->build_ids || inject->sched_stat ||
	    inject->itrace_synth_opts.set) {
629
		inject->tool.mmap	  = perf_event__repipe_mmap;
630
		inject->tool.mmap2	  = perf_event__repipe_mmap2;
631
		inject->tool.fork	  = perf_event__repipe_fork;
632
		inject->tool.tracing_data = perf_event__repipe_tracing_data;
T
Tom Zanussi 已提交
633 634
	}

635 636
	output_data_offset = session->header.data_offset;

637 638 639
	if (inject->build_ids) {
		inject->tool.sample = perf_event__inject_buildid;
	} else if (inject->sched_stat) {
640 641
		struct perf_evsel *evsel;

642
		evlist__for_each(session->evlist, evsel) {
643 644 645 646 647 648
			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;

649
				evsel->handler = perf_inject__sched_switch;
650
			} else if (!strcmp(name, "sched:sched_process_exit"))
651
				evsel->handler = perf_inject__sched_process_exit;
652
			else if (!strncmp(name, "sched:sched_stat_", 17))
653
				evsel->handler = perf_inject__sched_stat;
654
		}
655 656 657 658 659 660 661 662
	} 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;
		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;
663 664
		inject->tool.aux	    = perf_event__drop_aux;
		inject->tool.itrace_start   = perf_event__drop_aux,
665 666 667 668
		inject->tool.ordered_events = true;
		inject->tool.ordering_requires_timestamps = true;
		/* Allow space in the header for new attributes */
		output_data_offset = 4096;
669 670
		if (inject->strip)
			strip_init(inject);
671 672
	}

673 674 675
	if (!inject->itrace_synth_opts.set)
		auxtrace_index__free(&session->auxtrace_index);

676
	if (!file_out->is_pipe)
677
		lseek(fd, output_data_offset, SEEK_SET);
A
Andrew Vagin 已提交
678

679
	ret = perf_session__process_events(session);
T
Tom Zanussi 已提交
680

681
	if (!file_out->is_pipe) {
682
		if (inject->build_ids)
683 684
			perf_header__set_feat(&session->header,
					      HEADER_BUILD_ID);
685 686 687 688 689 690 691
		/*
		 * 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);
692 693
		/*
		 * The AUX areas have been removed and replaced with
694 695
		 * synthesized hardware events, so clear the feature flag and
		 * remove the evsel.
696
		 */
697
		if (inject->itrace_synth_opts.set) {
698 699
			struct perf_evsel *evsel;

700 701
			perf_header__clear_feat(&session->header,
						HEADER_AUXTRACE);
702 703 704
			if (inject->itrace_synth_opts.last_branch)
				perf_header__set_feat(&session->header,
						      HEADER_BRANCH_STACK);
705 706 707 708 709 710 711 712
			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);
			}
713 714
			if (inject->strip)
				strip_fini(inject);
715
		}
716
		session->header.data_offset = output_data_offset;
A
Andrew Vagin 已提交
717
		session->header.data_size = inject->bytes_written;
718
		perf_session__write_header(session, session->evlist, fd, true);
A
Andrew Vagin 已提交
719 720
	}

T
Tom Zanussi 已提交
721 722 723
	return ret;
}

724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
#ifdef HAVE_LIBELF_SUPPORT
static int
jit_validate_events(struct perf_session *session)
{
	struct perf_evsel *evsel;

	/*
	 * check that all events use CLOCK_MONOTONIC
	 */
	evlist__for_each(session->evlist, evsel) {
		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
			return -1;
	}
	return 0;
}
#endif

741
int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
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
			.finished_round	= perf_event__repipe_oe_synth,
765
			.build_id	= perf_event__repipe_op2_synth,
A
Adrian Hunter 已提交
766
			.id_index	= perf_event__repipe_op2_synth,
767
		},
A
Andrew Vagin 已提交
768
		.input_name  = "-",
769
		.samples = LIST_HEAD_INIT(inject.samples),
770 771 772 773
		.output = {
			.path = "-",
			.mode = PERF_DATA_MODE_WRITE,
		},
774
	};
775 776 777 778 779
	struct perf_data_file file = {
		.mode = PERF_DATA_MODE_READ,
	};
	int ret;

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

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

818 819 820 821 822
	if (inject.strip && !inject.itrace_synth_opts.set) {
		pr_err("--strip option requires --itrace option\n");
		return -1;
	}

823 824 825
	if (perf_data_file__open(&inject.output)) {
		perror("failed to create output file");
		return -1;
A
Andrew Vagin 已提交
826 827
	}

828 829
	inject.tool.ordered_events = inject.sched_stat;

830 831 832
	file.path = inject.input_name;
	inject.session = perf_session__new(&file, true, &inject.tool);
	if (inject.session == NULL)
833
		return -1;
834

835 836 837 838 839 840 841 842 843 844
	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;
	}
845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
#ifdef HAVE_LIBELF_SUPPORT
	if (inject.jit_mode) {
		/*
		 * validate event is using the correct clockid
		 */
		if (jit_validate_events(inject.session)) {
			fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
			return -1;
		}
		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
}