return perf_event__repipe_synth(tool, event);
}
+static int perf_event__repipe_synth_cb(const struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ return perf_event__repipe_synth(tool, event);
+}
+
static int perf_event__repipe_attr(const struct perf_tool *tool,
union perf_event *event,
struct evlist **pevlist)
{
struct perf_inject *inject = container_of(tool, struct perf_inject,
tool);
+ struct perf_event_attr attr;
+ size_t n_ids;
+ u64 *ids;
int ret;
ret = perf_event__process_attr(tool, event, pevlist);
if (!inject->output.is_pipe)
return 0;
- return perf_event__repipe_synth(tool, event);
+ if (!inject->itrace_synth_opts.set)
+ return perf_event__repipe_synth(tool, event);
+
+ if (event->header.size < sizeof(struct perf_event_header) + sizeof(u64)) {
+ pr_err("Attribute event size %u is too small\n", event->header.size);
+ return -EINVAL;
+ }
+
+ if (event->header.size - sizeof(event->header) < event->attr.attr.size) {
+ pr_err("Attribute event size %u is too small for attr.size %u\n",
+ event->header.size, event->attr.attr.size);
+ return -EINVAL;
+ }
+
+ memset(&attr, 0, sizeof(attr));
+ memcpy(&attr, &event->attr.attr,
+ min_t(size_t, sizeof(attr), (size_t)event->attr.attr.size));
+
+ n_ids = event->header.size - sizeof(event->header) - event->attr.attr.size;
+ n_ids /= sizeof(u64);
+ ids = perf_record_header_attr_id(event);
+
+ attr.size = sizeof(struct perf_event_attr);
+ attr.sample_type &= ~PERF_SAMPLE_AUX;
+
+ if (inject->itrace_synth_opts.add_last_branch) {
+ attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+ attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
+ }
+ return perf_event__synthesize_attr(tool, &attr, (u32)n_ids, ids,
+ perf_event__repipe_synth_cb);
}
static int perf_event__repipe_event_update(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample)
{
- size_t sz1 = sample->aux_sample.data - (void *)event;
- size_t sz2 = event->header.size - sample->aux_sample.size - sz1;
+ size_t sz1 = sample->aux_sample.data - (void *)event - sizeof(u64);
+ size_t sz2 = event->header.size - sample->aux_sample.size - (sz1 + sizeof(u64));
union perf_event *ev;
if (inject->event_copy == NULL) {
ev = (union perf_event *)inject->event_copy;
if (sz1 > event->header.size || sz2 > event->header.size ||
sz1 + sz2 > event->header.size ||
- sz1 < sizeof(struct perf_event_header) + sizeof(u64))
+ sz1 < sizeof(struct perf_event_header))
return event;
memcpy(ev, event, sz1);
memcpy((void *)ev + sz1, (void *)event + event->header.size - sz2, sz2);
ev->header.size = sz1 + sz2;
- ((u64 *)((void *)ev + sz1))[-1] = 0;
return ev;
}
struct perf_inject *inject = container_of(tool, struct perf_inject,
tool);
- if (evsel && evsel->handler) {
+ if (evsel == NULL)
+ return perf_event__repipe_synth(tool, event);
+
+ if (evsel->handler) {
inject_handler f = evsel->handler;
return f(tool, event, sample, evsel, machine);
}
build_id__mark_dso_hit(tool, event, sample, evsel, machine);
- if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
+ if (inject->itrace_synth_opts.set &&
+ (inject->itrace_synth_opts.last_branch ||
+ inject->itrace_synth_opts.add_last_branch)) {
+ union perf_event *event_copy = (void *)inject->event_copy;
+ struct branch_stack dummy_bs = { .nr = 0, .hw_idx = 0 };
+ int err;
+ size_t sz;
+ u64 orig_type = evsel->core.attr.sample_type;
+ u64 orig_branch_type = evsel->core.attr.branch_sample_type;
+
+ struct branch_stack *orig_bs = sample->branch_stack;
+
+ if (event_copy == NULL) {
+ inject->event_copy = malloc(PERF_SAMPLE_MAX_SIZE);
+ if (!inject->event_copy)
+ return -ENOMEM;
+
+ event_copy = (void *)inject->event_copy;
+ }
+
+ if (!sample->branch_stack)
+ sample->branch_stack = &dummy_bs;
+
+ if (inject->itrace_synth_opts.add_last_branch) {
+ /* Temporarily add in type bits for synthesis. */
+ evsel->core.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+ evsel->core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
+ }
+ evsel->core.attr.sample_type &= ~PERF_SAMPLE_AUX;
+
+ sz = perf_event__sample_event_size(sample, evsel->core.attr.sample_type,
+ evsel->core.attr.read_format,
+ evsel->core.attr.branch_sample_type);
+
+ if (sz >= PERF_SAMPLE_MAX_SIZE) {
+ pr_err("Sample size %zu exceeds max size %d\n", sz, PERF_SAMPLE_MAX_SIZE);
+ evsel->core.attr.sample_type = orig_type;
+ evsel->core.attr.branch_sample_type = orig_branch_type;
+ sample->branch_stack = orig_bs;
+ return -EFAULT;
+ }
+
+ event_copy->header.type = PERF_RECORD_SAMPLE;
+ event_copy->header.misc = event->header.misc;
+ event_copy->header.size = sz;
+
+ err = perf_event__synthesize_sample(event_copy, evsel->core.attr.sample_type,
+ evsel->core.attr.read_format,
+ evsel->core.attr.branch_sample_type, sample);
+
+ evsel->core.attr.sample_type = orig_type;
+ evsel->core.attr.branch_sample_type = orig_branch_type;
+ sample->branch_stack = orig_bs;
+
+ if (err) {
+ pr_err("Failed to synthesize sample\n");
+ return err;
+ }
+ event = event_copy;
+ } else if (inject->itrace_synth_opts.set &&
+ (evsel->core.attr.sample_type & PERF_SAMPLE_AUX)) {
event = perf_inject__cut_auxtrace_sample(inject, event, sample);
if (IS_ERR(event))
return PTR_ERR(event);
struct callchain_cursor_node *node;
struct thread *thread;
u64 sample_type = evsel->core.attr.sample_type;
- u32 sample_size = event->header.size;
+ size_t sz;
u64 i, k;
int ret;
out:
memcpy(event_copy, event, sizeof(event->header));
- /* adjust sample size for stack and regs */
- sample_size -= sample->user_stack.size;
- sample_size -= (hweight64(evsel->core.attr.sample_regs_user) + 1) * sizeof(u64);
- sample_size += (sample->callchain->nr + 1) * sizeof(u64);
- event_copy->header.size = sample_size;
-
/* remove sample_type {STACK,REGS}_USER for synthesize */
sample_type &= ~(PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER);
+ sz = perf_event__sample_event_size(sample, sample_type,
+ evsel->core.attr.read_format,
+ evsel->core.attr.branch_sample_type);
+ if (sz >= PERF_SAMPLE_MAX_SIZE) {
+ pr_err("Sample size %zu exceeds max size %d\n", sz, PERF_SAMPLE_MAX_SIZE);
+ return -EFAULT;
+ }
+ event_copy->header.size = sz;
+
ret = perf_event__synthesize_sample(event_copy, sample_type,
evsel->core.attr.read_format,
evsel->core.attr.branch_sample_type, sample);
* synthesized hardware events, so clear the feature flag.
*/
if (inject->itrace_synth_opts.set) {
+ struct evsel *evsel;
+
perf_header__clear_feat(&session->header,
HEADER_AUXTRACE);
- if (inject->itrace_synth_opts.last_branch ||
- inject->itrace_synth_opts.add_last_branch)
+
+ evlist__for_each_entry(session->evlist, evsel) {
+ evsel->core.attr.sample_type &= ~PERF_SAMPLE_AUX;
+ }
+
+ if (inject->itrace_synth_opts.add_last_branch) {
perf_header__set_feat(&session->header,
HEADER_BRANCH_STACK);
+
+ evlist__for_each_entry(session->evlist, evsel) {
+ evsel->core.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+ if (evsel->core.attr.size < PERF_ATTR_SIZE_VER2)
+ evsel->core.attr.size = PERF_ATTR_SIZE_VER2;
+ evsel->core.attr.branch_sample_type |=
+ PERF_SAMPLE_BRANCH_HW_INDEX;
+ }
+ }
}
/*