162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * intel_pt.c: Intel Processor Trace support
462306a36Sopenharmony_ci * Copyright (c) 2013-2015, Intel Corporation.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <inttypes.h>
862306a36Sopenharmony_ci#include <linux/perf_event.h>
962306a36Sopenharmony_ci#include <stdio.h>
1062306a36Sopenharmony_ci#include <stdbool.h>
1162306a36Sopenharmony_ci#include <errno.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/string.h>
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci#include <linux/zalloc.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "session.h"
1862306a36Sopenharmony_ci#include "machine.h"
1962306a36Sopenharmony_ci#include "memswap.h"
2062306a36Sopenharmony_ci#include "sort.h"
2162306a36Sopenharmony_ci#include "tool.h"
2262306a36Sopenharmony_ci#include "event.h"
2362306a36Sopenharmony_ci#include "evlist.h"
2462306a36Sopenharmony_ci#include "evsel.h"
2562306a36Sopenharmony_ci#include "map.h"
2662306a36Sopenharmony_ci#include "color.h"
2762306a36Sopenharmony_ci#include "thread.h"
2862306a36Sopenharmony_ci#include "thread-stack.h"
2962306a36Sopenharmony_ci#include "symbol.h"
3062306a36Sopenharmony_ci#include "callchain.h"
3162306a36Sopenharmony_ci#include "dso.h"
3262306a36Sopenharmony_ci#include "debug.h"
3362306a36Sopenharmony_ci#include "auxtrace.h"
3462306a36Sopenharmony_ci#include "tsc.h"
3562306a36Sopenharmony_ci#include "intel-pt.h"
3662306a36Sopenharmony_ci#include "config.h"
3762306a36Sopenharmony_ci#include "util/perf_api_probe.h"
3862306a36Sopenharmony_ci#include "util/synthetic-events.h"
3962306a36Sopenharmony_ci#include "time-utils.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "../arch/x86/include/uapi/asm/perf_regs.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include "intel-pt-decoder/intel-pt-log.h"
4462306a36Sopenharmony_ci#include "intel-pt-decoder/intel-pt-decoder.h"
4562306a36Sopenharmony_ci#include "intel-pt-decoder/intel-pt-insn-decoder.h"
4662306a36Sopenharmony_ci#include "intel-pt-decoder/intel-pt-pkt-decoder.h"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define MAX_TIMESTAMP (~0ULL)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define INTEL_PT_CFG_PASS_THRU	BIT_ULL(0)
5162306a36Sopenharmony_ci#define INTEL_PT_CFG_PWR_EVT_EN	BIT_ULL(4)
5262306a36Sopenharmony_ci#define INTEL_PT_CFG_BRANCH_EN	BIT_ULL(13)
5362306a36Sopenharmony_ci#define INTEL_PT_CFG_EVT_EN	BIT_ULL(31)
5462306a36Sopenharmony_ci#define INTEL_PT_CFG_TNT_DIS	BIT_ULL(55)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct range {
5762306a36Sopenharmony_ci	u64 start;
5862306a36Sopenharmony_ci	u64 end;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct intel_pt {
6262306a36Sopenharmony_ci	struct auxtrace auxtrace;
6362306a36Sopenharmony_ci	struct auxtrace_queues queues;
6462306a36Sopenharmony_ci	struct auxtrace_heap heap;
6562306a36Sopenharmony_ci	u32 auxtrace_type;
6662306a36Sopenharmony_ci	struct perf_session *session;
6762306a36Sopenharmony_ci	struct machine *machine;
6862306a36Sopenharmony_ci	struct evsel *switch_evsel;
6962306a36Sopenharmony_ci	struct thread *unknown_thread;
7062306a36Sopenharmony_ci	bool timeless_decoding;
7162306a36Sopenharmony_ci	bool sampling_mode;
7262306a36Sopenharmony_ci	bool snapshot_mode;
7362306a36Sopenharmony_ci	bool per_cpu_mmaps;
7462306a36Sopenharmony_ci	bool have_tsc;
7562306a36Sopenharmony_ci	bool data_queued;
7662306a36Sopenharmony_ci	bool est_tsc;
7762306a36Sopenharmony_ci	bool sync_switch;
7862306a36Sopenharmony_ci	bool sync_switch_not_supported;
7962306a36Sopenharmony_ci	bool mispred_all;
8062306a36Sopenharmony_ci	bool use_thread_stack;
8162306a36Sopenharmony_ci	bool callstack;
8262306a36Sopenharmony_ci	bool cap_event_trace;
8362306a36Sopenharmony_ci	bool have_guest_sideband;
8462306a36Sopenharmony_ci	unsigned int br_stack_sz;
8562306a36Sopenharmony_ci	unsigned int br_stack_sz_plus;
8662306a36Sopenharmony_ci	int have_sched_switch;
8762306a36Sopenharmony_ci	u32 pmu_type;
8862306a36Sopenharmony_ci	u64 kernel_start;
8962306a36Sopenharmony_ci	u64 switch_ip;
9062306a36Sopenharmony_ci	u64 ptss_ip;
9162306a36Sopenharmony_ci	u64 first_timestamp;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	struct perf_tsc_conversion tc;
9462306a36Sopenharmony_ci	bool cap_user_time_zero;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	struct itrace_synth_opts synth_opts;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	bool sample_instructions;
9962306a36Sopenharmony_ci	u64 instructions_sample_type;
10062306a36Sopenharmony_ci	u64 instructions_id;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	bool sample_cycles;
10362306a36Sopenharmony_ci	u64 cycles_sample_type;
10462306a36Sopenharmony_ci	u64 cycles_id;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	bool sample_branches;
10762306a36Sopenharmony_ci	u32 branches_filter;
10862306a36Sopenharmony_ci	u64 branches_sample_type;
10962306a36Sopenharmony_ci	u64 branches_id;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	bool sample_transactions;
11262306a36Sopenharmony_ci	u64 transactions_sample_type;
11362306a36Sopenharmony_ci	u64 transactions_id;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	bool sample_ptwrites;
11662306a36Sopenharmony_ci	u64 ptwrites_sample_type;
11762306a36Sopenharmony_ci	u64 ptwrites_id;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	bool sample_pwr_events;
12062306a36Sopenharmony_ci	u64 pwr_events_sample_type;
12162306a36Sopenharmony_ci	u64 mwait_id;
12262306a36Sopenharmony_ci	u64 pwre_id;
12362306a36Sopenharmony_ci	u64 exstop_id;
12462306a36Sopenharmony_ci	u64 pwrx_id;
12562306a36Sopenharmony_ci	u64 cbr_id;
12662306a36Sopenharmony_ci	u64 psb_id;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	bool single_pebs;
12962306a36Sopenharmony_ci	bool sample_pebs;
13062306a36Sopenharmony_ci	struct evsel *pebs_evsel;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	u64 evt_sample_type;
13362306a36Sopenharmony_ci	u64 evt_id;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	u64 iflag_chg_sample_type;
13662306a36Sopenharmony_ci	u64 iflag_chg_id;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	u64 tsc_bit;
13962306a36Sopenharmony_ci	u64 mtc_bit;
14062306a36Sopenharmony_ci	u64 mtc_freq_bits;
14162306a36Sopenharmony_ci	u32 tsc_ctc_ratio_n;
14262306a36Sopenharmony_ci	u32 tsc_ctc_ratio_d;
14362306a36Sopenharmony_ci	u64 cyc_bit;
14462306a36Sopenharmony_ci	u64 noretcomp_bit;
14562306a36Sopenharmony_ci	unsigned max_non_turbo_ratio;
14662306a36Sopenharmony_ci	unsigned cbr2khz;
14762306a36Sopenharmony_ci	int max_loops;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	unsigned long num_events;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	char *filter;
15262306a36Sopenharmony_ci	struct addr_filters filts;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	struct range *time_ranges;
15562306a36Sopenharmony_ci	unsigned int range_cnt;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	struct ip_callchain *chain;
15862306a36Sopenharmony_ci	struct branch_stack *br_stack;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	u64 dflt_tsc_offset;
16162306a36Sopenharmony_ci	struct rb_root vmcs_info;
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cienum switch_state {
16562306a36Sopenharmony_ci	INTEL_PT_SS_NOT_TRACING,
16662306a36Sopenharmony_ci	INTEL_PT_SS_UNKNOWN,
16762306a36Sopenharmony_ci	INTEL_PT_SS_TRACING,
16862306a36Sopenharmony_ci	INTEL_PT_SS_EXPECTING_SWITCH_EVENT,
16962306a36Sopenharmony_ci	INTEL_PT_SS_EXPECTING_SWITCH_IP,
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/* applicable_counters is 64-bits */
17362306a36Sopenharmony_ci#define INTEL_PT_MAX_PEBS 64
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistruct intel_pt_pebs_event {
17662306a36Sopenharmony_ci	struct evsel *evsel;
17762306a36Sopenharmony_ci	u64 id;
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistruct intel_pt_queue {
18162306a36Sopenharmony_ci	struct intel_pt *pt;
18262306a36Sopenharmony_ci	unsigned int queue_nr;
18362306a36Sopenharmony_ci	struct auxtrace_buffer *buffer;
18462306a36Sopenharmony_ci	struct auxtrace_buffer *old_buffer;
18562306a36Sopenharmony_ci	void *decoder;
18662306a36Sopenharmony_ci	const struct intel_pt_state *state;
18762306a36Sopenharmony_ci	struct ip_callchain *chain;
18862306a36Sopenharmony_ci	struct branch_stack *last_branch;
18962306a36Sopenharmony_ci	union perf_event *event_buf;
19062306a36Sopenharmony_ci	bool on_heap;
19162306a36Sopenharmony_ci	bool stop;
19262306a36Sopenharmony_ci	bool step_through_buffers;
19362306a36Sopenharmony_ci	bool use_buffer_pid_tid;
19462306a36Sopenharmony_ci	bool sync_switch;
19562306a36Sopenharmony_ci	bool sample_ipc;
19662306a36Sopenharmony_ci	pid_t pid, tid;
19762306a36Sopenharmony_ci	int cpu;
19862306a36Sopenharmony_ci	int switch_state;
19962306a36Sopenharmony_ci	pid_t next_tid;
20062306a36Sopenharmony_ci	struct thread *thread;
20162306a36Sopenharmony_ci	struct machine *guest_machine;
20262306a36Sopenharmony_ci	struct thread *guest_thread;
20362306a36Sopenharmony_ci	struct thread *unknown_guest_thread;
20462306a36Sopenharmony_ci	pid_t guest_machine_pid;
20562306a36Sopenharmony_ci	pid_t guest_pid;
20662306a36Sopenharmony_ci	pid_t guest_tid;
20762306a36Sopenharmony_ci	int vcpu;
20862306a36Sopenharmony_ci	bool exclude_kernel;
20962306a36Sopenharmony_ci	bool have_sample;
21062306a36Sopenharmony_ci	u64 time;
21162306a36Sopenharmony_ci	u64 timestamp;
21262306a36Sopenharmony_ci	u64 sel_timestamp;
21362306a36Sopenharmony_ci	bool sel_start;
21462306a36Sopenharmony_ci	unsigned int sel_idx;
21562306a36Sopenharmony_ci	u32 flags;
21662306a36Sopenharmony_ci	u16 insn_len;
21762306a36Sopenharmony_ci	u64 last_insn_cnt;
21862306a36Sopenharmony_ci	u64 ipc_insn_cnt;
21962306a36Sopenharmony_ci	u64 ipc_cyc_cnt;
22062306a36Sopenharmony_ci	u64 last_in_insn_cnt;
22162306a36Sopenharmony_ci	u64 last_in_cyc_cnt;
22262306a36Sopenharmony_ci	u64 last_cy_insn_cnt;
22362306a36Sopenharmony_ci	u64 last_cy_cyc_cnt;
22462306a36Sopenharmony_ci	u64 last_br_insn_cnt;
22562306a36Sopenharmony_ci	u64 last_br_cyc_cnt;
22662306a36Sopenharmony_ci	unsigned int cbr_seen;
22762306a36Sopenharmony_ci	char insn[INTEL_PT_INSN_BUF_SZ];
22862306a36Sopenharmony_ci	struct intel_pt_pebs_event pebs[INTEL_PT_MAX_PEBS];
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic void intel_pt_dump(struct intel_pt *pt __maybe_unused,
23262306a36Sopenharmony_ci			  unsigned char *buf, size_t len)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct intel_pt_pkt packet;
23562306a36Sopenharmony_ci	size_t pos = 0;
23662306a36Sopenharmony_ci	int ret, pkt_len, i;
23762306a36Sopenharmony_ci	char desc[INTEL_PT_PKT_DESC_MAX];
23862306a36Sopenharmony_ci	const char *color = PERF_COLOR_BLUE;
23962306a36Sopenharmony_ci	enum intel_pt_pkt_ctx ctx = INTEL_PT_NO_CTX;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	color_fprintf(stdout, color,
24262306a36Sopenharmony_ci		      ". ... Intel Processor Trace data: size %zu bytes\n",
24362306a36Sopenharmony_ci		      len);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	while (len) {
24662306a36Sopenharmony_ci		ret = intel_pt_get_packet(buf, len, &packet, &ctx);
24762306a36Sopenharmony_ci		if (ret > 0)
24862306a36Sopenharmony_ci			pkt_len = ret;
24962306a36Sopenharmony_ci		else
25062306a36Sopenharmony_ci			pkt_len = 1;
25162306a36Sopenharmony_ci		printf(".");
25262306a36Sopenharmony_ci		color_fprintf(stdout, color, "  %08x: ", pos);
25362306a36Sopenharmony_ci		for (i = 0; i < pkt_len; i++)
25462306a36Sopenharmony_ci			color_fprintf(stdout, color, " %02x", buf[i]);
25562306a36Sopenharmony_ci		for (; i < 16; i++)
25662306a36Sopenharmony_ci			color_fprintf(stdout, color, "   ");
25762306a36Sopenharmony_ci		if (ret > 0) {
25862306a36Sopenharmony_ci			ret = intel_pt_pkt_desc(&packet, desc,
25962306a36Sopenharmony_ci						INTEL_PT_PKT_DESC_MAX);
26062306a36Sopenharmony_ci			if (ret > 0)
26162306a36Sopenharmony_ci				color_fprintf(stdout, color, " %s\n", desc);
26262306a36Sopenharmony_ci		} else {
26362306a36Sopenharmony_ci			color_fprintf(stdout, color, " Bad packet!\n");
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci		pos += pkt_len;
26662306a36Sopenharmony_ci		buf += pkt_len;
26762306a36Sopenharmony_ci		len -= pkt_len;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void intel_pt_dump_event(struct intel_pt *pt, unsigned char *buf,
27262306a36Sopenharmony_ci				size_t len)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	printf(".\n");
27562306a36Sopenharmony_ci	intel_pt_dump(pt, buf, len);
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic void intel_pt_log_event(union perf_event *event)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	FILE *f = intel_pt_log_fp();
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (!intel_pt_enable_logging || !f)
28362306a36Sopenharmony_ci		return;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	perf_event__fprintf(event, NULL, f);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic void intel_pt_dump_sample(struct perf_session *session,
28962306a36Sopenharmony_ci				 struct perf_sample *sample)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
29262306a36Sopenharmony_ci					   auxtrace);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	printf("\n");
29562306a36Sopenharmony_ci	intel_pt_dump(pt, sample->aux_sample.data, sample->aux_sample.size);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic bool intel_pt_log_events(struct intel_pt *pt, u64 tm)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct perf_time_interval *range = pt->synth_opts.ptime_range;
30162306a36Sopenharmony_ci	int n = pt->synth_opts.range_num;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (pt->synth_opts.log_plus_flags & AUXTRACE_LOG_FLG_ALL_PERF_EVTS)
30462306a36Sopenharmony_ci		return true;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (pt->synth_opts.log_minus_flags & AUXTRACE_LOG_FLG_ALL_PERF_EVTS)
30762306a36Sopenharmony_ci		return false;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* perf_time__ranges_skip_sample does not work if time is zero */
31062306a36Sopenharmony_ci	if (!tm)
31162306a36Sopenharmony_ci		tm = 1;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return !n || !perf_time__ranges_skip_sample(range, n, tm);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic struct intel_pt_vmcs_info *intel_pt_findnew_vmcs(struct rb_root *rb_root,
31762306a36Sopenharmony_ci							u64 vmcs,
31862306a36Sopenharmony_ci							u64 dflt_tsc_offset)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct rb_node **p = &rb_root->rb_node;
32162306a36Sopenharmony_ci	struct rb_node *parent = NULL;
32262306a36Sopenharmony_ci	struct intel_pt_vmcs_info *v;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	while (*p) {
32562306a36Sopenharmony_ci		parent = *p;
32662306a36Sopenharmony_ci		v = rb_entry(parent, struct intel_pt_vmcs_info, rb_node);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		if (v->vmcs == vmcs)
32962306a36Sopenharmony_ci			return v;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		if (vmcs < v->vmcs)
33262306a36Sopenharmony_ci			p = &(*p)->rb_left;
33362306a36Sopenharmony_ci		else
33462306a36Sopenharmony_ci			p = &(*p)->rb_right;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	v = zalloc(sizeof(*v));
33862306a36Sopenharmony_ci	if (v) {
33962306a36Sopenharmony_ci		v->vmcs = vmcs;
34062306a36Sopenharmony_ci		v->tsc_offset = dflt_tsc_offset;
34162306a36Sopenharmony_ci		v->reliable = dflt_tsc_offset;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		rb_link_node(&v->rb_node, parent, p);
34462306a36Sopenharmony_ci		rb_insert_color(&v->rb_node, rb_root);
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	return v;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic struct intel_pt_vmcs_info *intel_pt_findnew_vmcs_info(void *data, uint64_t vmcs)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct intel_pt_queue *ptq = data;
35362306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (!vmcs && !pt->dflt_tsc_offset)
35662306a36Sopenharmony_ci		return NULL;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return intel_pt_findnew_vmcs(&pt->vmcs_info, vmcs, pt->dflt_tsc_offset);
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic void intel_pt_free_vmcs_info(struct intel_pt *pt)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct intel_pt_vmcs_info *v;
36462306a36Sopenharmony_ci	struct rb_node *n;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	n = rb_first(&pt->vmcs_info);
36762306a36Sopenharmony_ci	while (n) {
36862306a36Sopenharmony_ci		v = rb_entry(n, struct intel_pt_vmcs_info, rb_node);
36962306a36Sopenharmony_ci		n = rb_next(n);
37062306a36Sopenharmony_ci		rb_erase(&v->rb_node, &pt->vmcs_info);
37162306a36Sopenharmony_ci		free(v);
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
37662306a36Sopenharmony_ci				   struct auxtrace_buffer *b)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	bool consecutive = false;
37962306a36Sopenharmony_ci	void *start;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	start = intel_pt_find_overlap(a->data, a->size, b->data, b->size,
38262306a36Sopenharmony_ci				      pt->have_tsc, &consecutive,
38362306a36Sopenharmony_ci				      pt->synth_opts.vm_time_correlation);
38462306a36Sopenharmony_ci	if (!start)
38562306a36Sopenharmony_ci		return -EINVAL;
38662306a36Sopenharmony_ci	/*
38762306a36Sopenharmony_ci	 * In the case of vm_time_correlation, the overlap might contain TSC
38862306a36Sopenharmony_ci	 * packets that will not be fixed, and that will then no longer work for
38962306a36Sopenharmony_ci	 * overlap detection. Avoid that by zeroing out the overlap.
39062306a36Sopenharmony_ci	 */
39162306a36Sopenharmony_ci	if (pt->synth_opts.vm_time_correlation)
39262306a36Sopenharmony_ci		memset(b->data, 0, start - b->data);
39362306a36Sopenharmony_ci	b->use_size = b->data + b->size - start;
39462306a36Sopenharmony_ci	b->use_data = start;
39562306a36Sopenharmony_ci	if (b->use_size && consecutive)
39662306a36Sopenharmony_ci		b->consecutive = true;
39762306a36Sopenharmony_ci	return 0;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic int intel_pt_get_buffer(struct intel_pt_queue *ptq,
40162306a36Sopenharmony_ci			       struct auxtrace_buffer *buffer,
40262306a36Sopenharmony_ci			       struct auxtrace_buffer *old_buffer,
40362306a36Sopenharmony_ci			       struct intel_pt_buffer *b)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	bool might_overlap;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (!buffer->data) {
40862306a36Sopenharmony_ci		int fd = perf_data__fd(ptq->pt->session->data);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		buffer->data = auxtrace_buffer__get_data(buffer, fd);
41162306a36Sopenharmony_ci		if (!buffer->data)
41262306a36Sopenharmony_ci			return -ENOMEM;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	might_overlap = ptq->pt->snapshot_mode || ptq->pt->sampling_mode;
41662306a36Sopenharmony_ci	if (might_overlap && !buffer->consecutive && old_buffer &&
41762306a36Sopenharmony_ci	    intel_pt_do_fix_overlap(ptq->pt, old_buffer, buffer))
41862306a36Sopenharmony_ci		return -ENOMEM;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (buffer->use_data) {
42162306a36Sopenharmony_ci		b->len = buffer->use_size;
42262306a36Sopenharmony_ci		b->buf = buffer->use_data;
42362306a36Sopenharmony_ci	} else {
42462306a36Sopenharmony_ci		b->len = buffer->size;
42562306a36Sopenharmony_ci		b->buf = buffer->data;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci	b->ref_timestamp = buffer->reference;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (!old_buffer || (might_overlap && !buffer->consecutive)) {
43062306a36Sopenharmony_ci		b->consecutive = false;
43162306a36Sopenharmony_ci		b->trace_nr = buffer->buffer_nr + 1;
43262306a36Sopenharmony_ci	} else {
43362306a36Sopenharmony_ci		b->consecutive = true;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return 0;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/* Do not drop buffers with references - refer intel_pt_get_trace() */
44062306a36Sopenharmony_cistatic void intel_pt_lookahead_drop_buffer(struct intel_pt_queue *ptq,
44162306a36Sopenharmony_ci					   struct auxtrace_buffer *buffer)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	if (!buffer || buffer == ptq->buffer || buffer == ptq->old_buffer)
44462306a36Sopenharmony_ci		return;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	auxtrace_buffer__drop_data(buffer);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci/* Must be serialized with respect to intel_pt_get_trace() */
45062306a36Sopenharmony_cistatic int intel_pt_lookahead(void *data, intel_pt_lookahead_cb_t cb,
45162306a36Sopenharmony_ci			      void *cb_data)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct intel_pt_queue *ptq = data;
45462306a36Sopenharmony_ci	struct auxtrace_buffer *buffer = ptq->buffer;
45562306a36Sopenharmony_ci	struct auxtrace_buffer *old_buffer = ptq->old_buffer;
45662306a36Sopenharmony_ci	struct auxtrace_queue *queue;
45762306a36Sopenharmony_ci	int err = 0;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	queue = &ptq->pt->queues.queue_array[ptq->queue_nr];
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	while (1) {
46262306a36Sopenharmony_ci		struct intel_pt_buffer b = { .len = 0 };
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		buffer = auxtrace_buffer__next(queue, buffer);
46562306a36Sopenharmony_ci		if (!buffer)
46662306a36Sopenharmony_ci			break;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		err = intel_pt_get_buffer(ptq, buffer, old_buffer, &b);
46962306a36Sopenharmony_ci		if (err)
47062306a36Sopenharmony_ci			break;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		if (b.len) {
47362306a36Sopenharmony_ci			intel_pt_lookahead_drop_buffer(ptq, old_buffer);
47462306a36Sopenharmony_ci			old_buffer = buffer;
47562306a36Sopenharmony_ci		} else {
47662306a36Sopenharmony_ci			intel_pt_lookahead_drop_buffer(ptq, buffer);
47762306a36Sopenharmony_ci			continue;
47862306a36Sopenharmony_ci		}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		err = cb(&b, cb_data);
48162306a36Sopenharmony_ci		if (err)
48262306a36Sopenharmony_ci			break;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (buffer != old_buffer)
48662306a36Sopenharmony_ci		intel_pt_lookahead_drop_buffer(ptq, buffer);
48762306a36Sopenharmony_ci	intel_pt_lookahead_drop_buffer(ptq, old_buffer);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return err;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/*
49362306a36Sopenharmony_ci * This function assumes data is processed sequentially only.
49462306a36Sopenharmony_ci * Must be serialized with respect to intel_pt_lookahead()
49562306a36Sopenharmony_ci */
49662306a36Sopenharmony_cistatic int intel_pt_get_trace(struct intel_pt_buffer *b, void *data)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct intel_pt_queue *ptq = data;
49962306a36Sopenharmony_ci	struct auxtrace_buffer *buffer = ptq->buffer;
50062306a36Sopenharmony_ci	struct auxtrace_buffer *old_buffer = ptq->old_buffer;
50162306a36Sopenharmony_ci	struct auxtrace_queue *queue;
50262306a36Sopenharmony_ci	int err;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (ptq->stop) {
50562306a36Sopenharmony_ci		b->len = 0;
50662306a36Sopenharmony_ci		return 0;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	queue = &ptq->pt->queues.queue_array[ptq->queue_nr];
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	buffer = auxtrace_buffer__next(queue, buffer);
51262306a36Sopenharmony_ci	if (!buffer) {
51362306a36Sopenharmony_ci		if (old_buffer)
51462306a36Sopenharmony_ci			auxtrace_buffer__drop_data(old_buffer);
51562306a36Sopenharmony_ci		b->len = 0;
51662306a36Sopenharmony_ci		return 0;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	ptq->buffer = buffer;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	err = intel_pt_get_buffer(ptq, buffer, old_buffer, b);
52262306a36Sopenharmony_ci	if (err)
52362306a36Sopenharmony_ci		return err;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (ptq->step_through_buffers)
52662306a36Sopenharmony_ci		ptq->stop = true;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (b->len) {
52962306a36Sopenharmony_ci		if (old_buffer)
53062306a36Sopenharmony_ci			auxtrace_buffer__drop_data(old_buffer);
53162306a36Sopenharmony_ci		ptq->old_buffer = buffer;
53262306a36Sopenharmony_ci	} else {
53362306a36Sopenharmony_ci		auxtrace_buffer__drop_data(buffer);
53462306a36Sopenharmony_ci		return intel_pt_get_trace(b, data);
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return 0;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistruct intel_pt_cache_entry {
54162306a36Sopenharmony_ci	struct auxtrace_cache_entry	entry;
54262306a36Sopenharmony_ci	u64				insn_cnt;
54362306a36Sopenharmony_ci	u64				byte_cnt;
54462306a36Sopenharmony_ci	enum intel_pt_insn_op		op;
54562306a36Sopenharmony_ci	enum intel_pt_insn_branch	branch;
54662306a36Sopenharmony_ci	bool				emulated_ptwrite;
54762306a36Sopenharmony_ci	int				length;
54862306a36Sopenharmony_ci	int32_t				rel;
54962306a36Sopenharmony_ci	char				insn[INTEL_PT_INSN_BUF_SZ];
55062306a36Sopenharmony_ci};
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic int intel_pt_config_div(const char *var, const char *value, void *data)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	int *d = data;
55562306a36Sopenharmony_ci	long val;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (!strcmp(var, "intel-pt.cache-divisor")) {
55862306a36Sopenharmony_ci		val = strtol(value, NULL, 0);
55962306a36Sopenharmony_ci		if (val > 0 && val <= INT_MAX)
56062306a36Sopenharmony_ci			*d = val;
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return 0;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic int intel_pt_cache_divisor(void)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	static int d;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (d)
57162306a36Sopenharmony_ci		return d;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	perf_config(intel_pt_config_div, &d);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (!d)
57662306a36Sopenharmony_ci		d = 64;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	return d;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic unsigned int intel_pt_cache_size(struct dso *dso,
58262306a36Sopenharmony_ci					struct machine *machine)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	off_t size;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	size = dso__data_size(dso, machine);
58762306a36Sopenharmony_ci	size /= intel_pt_cache_divisor();
58862306a36Sopenharmony_ci	if (size < 1000)
58962306a36Sopenharmony_ci		return 10;
59062306a36Sopenharmony_ci	if (size > (1 << 21))
59162306a36Sopenharmony_ci		return 21;
59262306a36Sopenharmony_ci	return 32 - __builtin_clz(size);
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic struct auxtrace_cache *intel_pt_cache(struct dso *dso,
59662306a36Sopenharmony_ci					     struct machine *machine)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct auxtrace_cache *c;
59962306a36Sopenharmony_ci	unsigned int bits;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (dso->auxtrace_cache)
60262306a36Sopenharmony_ci		return dso->auxtrace_cache;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	bits = intel_pt_cache_size(dso, machine);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/* Ignoring cache creation failure */
60762306a36Sopenharmony_ci	c = auxtrace_cache__new(bits, sizeof(struct intel_pt_cache_entry), 200);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	dso->auxtrace_cache = c;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	return c;
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic int intel_pt_cache_add(struct dso *dso, struct machine *machine,
61562306a36Sopenharmony_ci			      u64 offset, u64 insn_cnt, u64 byte_cnt,
61662306a36Sopenharmony_ci			      struct intel_pt_insn *intel_pt_insn)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct auxtrace_cache *c = intel_pt_cache(dso, machine);
61962306a36Sopenharmony_ci	struct intel_pt_cache_entry *e;
62062306a36Sopenharmony_ci	int err;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (!c)
62362306a36Sopenharmony_ci		return -ENOMEM;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	e = auxtrace_cache__alloc_entry(c);
62662306a36Sopenharmony_ci	if (!e)
62762306a36Sopenharmony_ci		return -ENOMEM;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	e->insn_cnt = insn_cnt;
63062306a36Sopenharmony_ci	e->byte_cnt = byte_cnt;
63162306a36Sopenharmony_ci	e->op = intel_pt_insn->op;
63262306a36Sopenharmony_ci	e->branch = intel_pt_insn->branch;
63362306a36Sopenharmony_ci	e->emulated_ptwrite = intel_pt_insn->emulated_ptwrite;
63462306a36Sopenharmony_ci	e->length = intel_pt_insn->length;
63562306a36Sopenharmony_ci	e->rel = intel_pt_insn->rel;
63662306a36Sopenharmony_ci	memcpy(e->insn, intel_pt_insn->buf, INTEL_PT_INSN_BUF_SZ);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	err = auxtrace_cache__add(c, offset, &e->entry);
63962306a36Sopenharmony_ci	if (err)
64062306a36Sopenharmony_ci		auxtrace_cache__free_entry(c, e);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	return err;
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic struct intel_pt_cache_entry *
64662306a36Sopenharmony_ciintel_pt_cache_lookup(struct dso *dso, struct machine *machine, u64 offset)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	struct auxtrace_cache *c = intel_pt_cache(dso, machine);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (!c)
65162306a36Sopenharmony_ci		return NULL;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	return auxtrace_cache__lookup(dso->auxtrace_cache, offset);
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic void intel_pt_cache_invalidate(struct dso *dso, struct machine *machine,
65762306a36Sopenharmony_ci				      u64 offset)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct auxtrace_cache *c = intel_pt_cache(dso, machine);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (!c)
66262306a36Sopenharmony_ci		return;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	auxtrace_cache__remove(dso->auxtrace_cache, offset);
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic inline bool intel_pt_guest_kernel_ip(uint64_t ip)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	/* Assumes 64-bit kernel */
67062306a36Sopenharmony_ci	return ip & (1ULL << 63);
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic inline u8 intel_pt_nr_cpumode(struct intel_pt_queue *ptq, uint64_t ip, bool nr)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	if (nr) {
67662306a36Sopenharmony_ci		return intel_pt_guest_kernel_ip(ip) ?
67762306a36Sopenharmony_ci		       PERF_RECORD_MISC_GUEST_KERNEL :
67862306a36Sopenharmony_ci		       PERF_RECORD_MISC_GUEST_USER;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	return ip >= ptq->pt->kernel_start ?
68262306a36Sopenharmony_ci	       PERF_RECORD_MISC_KERNEL :
68362306a36Sopenharmony_ci	       PERF_RECORD_MISC_USER;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic inline u8 intel_pt_cpumode(struct intel_pt_queue *ptq, uint64_t from_ip, uint64_t to_ip)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	/* No support for non-zero CS base */
68962306a36Sopenharmony_ci	if (from_ip)
69062306a36Sopenharmony_ci		return intel_pt_nr_cpumode(ptq, from_ip, ptq->state->from_nr);
69162306a36Sopenharmony_ci	return intel_pt_nr_cpumode(ptq, to_ip, ptq->state->to_nr);
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic int intel_pt_get_guest(struct intel_pt_queue *ptq)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct machines *machines = &ptq->pt->session->machines;
69762306a36Sopenharmony_ci	struct machine *machine;
69862306a36Sopenharmony_ci	pid_t pid = ptq->pid <= 0 ? DEFAULT_GUEST_KERNEL_ID : ptq->pid;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (ptq->guest_machine && pid == ptq->guest_machine->pid)
70162306a36Sopenharmony_ci		return 0;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	ptq->guest_machine = NULL;
70462306a36Sopenharmony_ci	thread__zput(ptq->unknown_guest_thread);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (symbol_conf.guest_code) {
70762306a36Sopenharmony_ci		thread__zput(ptq->guest_thread);
70862306a36Sopenharmony_ci		ptq->guest_thread = machines__findnew_guest_code(machines, pid);
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	machine = machines__find_guest(machines, pid);
71262306a36Sopenharmony_ci	if (!machine)
71362306a36Sopenharmony_ci		return -1;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	ptq->unknown_guest_thread = machine__idle_thread(machine);
71662306a36Sopenharmony_ci	if (!ptq->unknown_guest_thread)
71762306a36Sopenharmony_ci		return -1;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	ptq->guest_machine = machine;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	return 0;
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic inline bool intel_pt_jmp_16(struct intel_pt_insn *intel_pt_insn)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	return intel_pt_insn->rel == 16 && intel_pt_insn->branch == INTEL_PT_BR_UNCONDITIONAL;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci#define PTWRITE_MAGIC		"\x0f\x0bperf,ptwrite  "
73062306a36Sopenharmony_ci#define PTWRITE_MAGIC_LEN	16
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic bool intel_pt_emulated_ptwrite(struct dso *dso, struct machine *machine, u64 offset)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	unsigned char buf[PTWRITE_MAGIC_LEN];
73562306a36Sopenharmony_ci	ssize_t len;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	len = dso__data_read_offset(dso, machine, offset, buf, PTWRITE_MAGIC_LEN);
73862306a36Sopenharmony_ci	if (len == PTWRITE_MAGIC_LEN && !memcmp(buf, PTWRITE_MAGIC, PTWRITE_MAGIC_LEN)) {
73962306a36Sopenharmony_ci		intel_pt_log("Emulated ptwrite signature found\n");
74062306a36Sopenharmony_ci		return true;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci	intel_pt_log("Emulated ptwrite signature not found\n");
74362306a36Sopenharmony_ci	return false;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
74762306a36Sopenharmony_ci				   uint64_t *insn_cnt_ptr, uint64_t *ip,
74862306a36Sopenharmony_ci				   uint64_t to_ip, uint64_t max_insn_cnt,
74962306a36Sopenharmony_ci				   void *data)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	struct intel_pt_queue *ptq = data;
75262306a36Sopenharmony_ci	struct machine *machine = ptq->pt->machine;
75362306a36Sopenharmony_ci	struct thread *thread;
75462306a36Sopenharmony_ci	struct addr_location al;
75562306a36Sopenharmony_ci	unsigned char buf[INTEL_PT_INSN_BUF_SZ];
75662306a36Sopenharmony_ci	ssize_t len;
75762306a36Sopenharmony_ci	int x86_64, ret = 0;
75862306a36Sopenharmony_ci	u8 cpumode;
75962306a36Sopenharmony_ci	u64 offset, start_offset, start_ip;
76062306a36Sopenharmony_ci	u64 insn_cnt = 0;
76162306a36Sopenharmony_ci	bool one_map = true;
76262306a36Sopenharmony_ci	bool nr;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	addr_location__init(&al);
76662306a36Sopenharmony_ci	intel_pt_insn->length = 0;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	if (to_ip && *ip == to_ip)
76962306a36Sopenharmony_ci		goto out_no_cache;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	nr = ptq->state->to_nr;
77262306a36Sopenharmony_ci	cpumode = intel_pt_nr_cpumode(ptq, *ip, nr);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (nr) {
77562306a36Sopenharmony_ci		if (ptq->pt->have_guest_sideband) {
77662306a36Sopenharmony_ci			if (!ptq->guest_machine || ptq->guest_machine_pid != ptq->pid) {
77762306a36Sopenharmony_ci				intel_pt_log("ERROR: guest sideband but no guest machine\n");
77862306a36Sopenharmony_ci				ret = -EINVAL;
77962306a36Sopenharmony_ci				goto out_ret;
78062306a36Sopenharmony_ci			}
78162306a36Sopenharmony_ci		} else if ((!symbol_conf.guest_code && cpumode != PERF_RECORD_MISC_GUEST_KERNEL) ||
78262306a36Sopenharmony_ci			   intel_pt_get_guest(ptq)) {
78362306a36Sopenharmony_ci			intel_pt_log("ERROR: no guest machine\n");
78462306a36Sopenharmony_ci			ret = -EINVAL;
78562306a36Sopenharmony_ci			goto out_ret;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci		machine = ptq->guest_machine;
78862306a36Sopenharmony_ci		thread = ptq->guest_thread;
78962306a36Sopenharmony_ci		if (!thread) {
79062306a36Sopenharmony_ci			if (cpumode != PERF_RECORD_MISC_GUEST_KERNEL) {
79162306a36Sopenharmony_ci				intel_pt_log("ERROR: no guest thread\n");
79262306a36Sopenharmony_ci				ret = -EINVAL;
79362306a36Sopenharmony_ci				goto out_ret;
79462306a36Sopenharmony_ci			}
79562306a36Sopenharmony_ci			thread = ptq->unknown_guest_thread;
79662306a36Sopenharmony_ci		}
79762306a36Sopenharmony_ci	} else {
79862306a36Sopenharmony_ci		thread = ptq->thread;
79962306a36Sopenharmony_ci		if (!thread) {
80062306a36Sopenharmony_ci			if (cpumode != PERF_RECORD_MISC_KERNEL) {
80162306a36Sopenharmony_ci				intel_pt_log("ERROR: no thread\n");
80262306a36Sopenharmony_ci				ret = -EINVAL;
80362306a36Sopenharmony_ci				goto out_ret;
80462306a36Sopenharmony_ci			}
80562306a36Sopenharmony_ci			thread = ptq->pt->unknown_thread;
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	while (1) {
81062306a36Sopenharmony_ci		struct dso *dso;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		if (!thread__find_map(thread, cpumode, *ip, &al) || !map__dso(al.map)) {
81362306a36Sopenharmony_ci			if (al.map)
81462306a36Sopenharmony_ci				intel_pt_log("ERROR: thread has no dso for %#" PRIx64 "\n", *ip);
81562306a36Sopenharmony_ci			else
81662306a36Sopenharmony_ci				intel_pt_log("ERROR: thread has no map for %#" PRIx64 "\n", *ip);
81762306a36Sopenharmony_ci			addr_location__exit(&al);
81862306a36Sopenharmony_ci			ret = -EINVAL;
81962306a36Sopenharmony_ci			goto out_ret;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci		dso = map__dso(al.map);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		if (dso->data.status == DSO_DATA_STATUS_ERROR &&
82462306a36Sopenharmony_ci			dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE)) {
82562306a36Sopenharmony_ci			ret = -ENOENT;
82662306a36Sopenharmony_ci			goto out_ret;
82762306a36Sopenharmony_ci		}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		offset = map__map_ip(al.map, *ip);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		if (!to_ip && one_map) {
83262306a36Sopenharmony_ci			struct intel_pt_cache_entry *e;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci			e = intel_pt_cache_lookup(dso, machine, offset);
83562306a36Sopenharmony_ci			if (e &&
83662306a36Sopenharmony_ci			    (!max_insn_cnt || e->insn_cnt <= max_insn_cnt)) {
83762306a36Sopenharmony_ci				*insn_cnt_ptr = e->insn_cnt;
83862306a36Sopenharmony_ci				*ip += e->byte_cnt;
83962306a36Sopenharmony_ci				intel_pt_insn->op = e->op;
84062306a36Sopenharmony_ci				intel_pt_insn->branch = e->branch;
84162306a36Sopenharmony_ci				intel_pt_insn->emulated_ptwrite = e->emulated_ptwrite;
84262306a36Sopenharmony_ci				intel_pt_insn->length = e->length;
84362306a36Sopenharmony_ci				intel_pt_insn->rel = e->rel;
84462306a36Sopenharmony_ci				memcpy(intel_pt_insn->buf, e->insn, INTEL_PT_INSN_BUF_SZ);
84562306a36Sopenharmony_ci				intel_pt_log_insn_no_data(intel_pt_insn, *ip);
84662306a36Sopenharmony_ci				ret = 0;
84762306a36Sopenharmony_ci				goto out_ret;
84862306a36Sopenharmony_ci			}
84962306a36Sopenharmony_ci		}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		start_offset = offset;
85262306a36Sopenharmony_ci		start_ip = *ip;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		/* Load maps to ensure dso->is_64_bit has been updated */
85562306a36Sopenharmony_ci		map__load(al.map);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci		x86_64 = dso->is_64_bit;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci		while (1) {
86062306a36Sopenharmony_ci			len = dso__data_read_offset(dso, machine,
86162306a36Sopenharmony_ci						    offset, buf,
86262306a36Sopenharmony_ci						    INTEL_PT_INSN_BUF_SZ);
86362306a36Sopenharmony_ci			if (len <= 0) {
86462306a36Sopenharmony_ci				intel_pt_log("ERROR: failed to read at offset %#" PRIx64 " ",
86562306a36Sopenharmony_ci					     offset);
86662306a36Sopenharmony_ci				if (intel_pt_enable_logging)
86762306a36Sopenharmony_ci					dso__fprintf(dso, intel_pt_log_fp());
86862306a36Sopenharmony_ci				ret = -EINVAL;
86962306a36Sopenharmony_ci				goto out_ret;
87062306a36Sopenharmony_ci			}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci			if (intel_pt_get_insn(buf, len, x86_64, intel_pt_insn)) {
87362306a36Sopenharmony_ci				ret = -EINVAL;
87462306a36Sopenharmony_ci				goto out_ret;
87562306a36Sopenharmony_ci			}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci			intel_pt_log_insn(intel_pt_insn, *ip);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci			insn_cnt += 1;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci			if (intel_pt_insn->branch != INTEL_PT_BR_NO_BRANCH) {
88262306a36Sopenharmony_ci				bool eptw;
88362306a36Sopenharmony_ci				u64 offs;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci				if (!intel_pt_jmp_16(intel_pt_insn))
88662306a36Sopenharmony_ci					goto out;
88762306a36Sopenharmony_ci				/* Check for emulated ptwrite */
88862306a36Sopenharmony_ci				offs = offset + intel_pt_insn->length;
88962306a36Sopenharmony_ci				eptw = intel_pt_emulated_ptwrite(dso, machine, offs);
89062306a36Sopenharmony_ci				intel_pt_insn->emulated_ptwrite = eptw;
89162306a36Sopenharmony_ci				goto out;
89262306a36Sopenharmony_ci			}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci			if (max_insn_cnt && insn_cnt >= max_insn_cnt)
89562306a36Sopenharmony_ci				goto out_no_cache;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci			*ip += intel_pt_insn->length;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci			if (to_ip && *ip == to_ip) {
90062306a36Sopenharmony_ci				intel_pt_insn->length = 0;
90162306a36Sopenharmony_ci				goto out_no_cache;
90262306a36Sopenharmony_ci			}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci			if (*ip >= map__end(al.map))
90562306a36Sopenharmony_ci				break;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci			offset += intel_pt_insn->length;
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci		one_map = false;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ciout:
91262306a36Sopenharmony_ci	*insn_cnt_ptr = insn_cnt;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	if (!one_map)
91562306a36Sopenharmony_ci		goto out_no_cache;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	/*
91862306a36Sopenharmony_ci	 * Didn't lookup in the 'to_ip' case, so do it now to prevent duplicate
91962306a36Sopenharmony_ci	 * entries.
92062306a36Sopenharmony_ci	 */
92162306a36Sopenharmony_ci	if (to_ip) {
92262306a36Sopenharmony_ci		struct intel_pt_cache_entry *e;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci		e = intel_pt_cache_lookup(map__dso(al.map), machine, start_offset);
92562306a36Sopenharmony_ci		if (e)
92662306a36Sopenharmony_ci			goto out_ret;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/* Ignore cache errors */
93062306a36Sopenharmony_ci	intel_pt_cache_add(map__dso(al.map), machine, start_offset, insn_cnt,
93162306a36Sopenharmony_ci			   *ip - start_ip, intel_pt_insn);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ciout_ret:
93462306a36Sopenharmony_ci	addr_location__exit(&al);
93562306a36Sopenharmony_ci	return ret;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ciout_no_cache:
93862306a36Sopenharmony_ci	*insn_cnt_ptr = insn_cnt;
93962306a36Sopenharmony_ci	addr_location__exit(&al);
94062306a36Sopenharmony_ci	return 0;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic bool intel_pt_match_pgd_ip(struct intel_pt *pt, uint64_t ip,
94462306a36Sopenharmony_ci				  uint64_t offset, const char *filename)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct addr_filter *filt;
94762306a36Sopenharmony_ci	bool have_filter   = false;
94862306a36Sopenharmony_ci	bool hit_tracestop = false;
94962306a36Sopenharmony_ci	bool hit_filter    = false;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	list_for_each_entry(filt, &pt->filts.head, list) {
95262306a36Sopenharmony_ci		if (filt->start)
95362306a36Sopenharmony_ci			have_filter = true;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci		if ((filename && !filt->filename) ||
95662306a36Sopenharmony_ci		    (!filename && filt->filename) ||
95762306a36Sopenharmony_ci		    (filename && strcmp(filename, filt->filename)))
95862306a36Sopenharmony_ci			continue;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci		if (!(offset >= filt->addr && offset < filt->addr + filt->size))
96162306a36Sopenharmony_ci			continue;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		intel_pt_log("TIP.PGD ip %#"PRIx64" offset %#"PRIx64" in %s hit filter: %s offset %#"PRIx64" size %#"PRIx64"\n",
96462306a36Sopenharmony_ci			     ip, offset, filename ? filename : "[kernel]",
96562306a36Sopenharmony_ci			     filt->start ? "filter" : "stop",
96662306a36Sopenharmony_ci			     filt->addr, filt->size);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci		if (filt->start)
96962306a36Sopenharmony_ci			hit_filter = true;
97062306a36Sopenharmony_ci		else
97162306a36Sopenharmony_ci			hit_tracestop = true;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (!hit_tracestop && !hit_filter)
97562306a36Sopenharmony_ci		intel_pt_log("TIP.PGD ip %#"PRIx64" offset %#"PRIx64" in %s is not in a filter region\n",
97662306a36Sopenharmony_ci			     ip, offset, filename ? filename : "[kernel]");
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return hit_tracestop || (have_filter && !hit_filter);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic int __intel_pt_pgd_ip(uint64_t ip, void *data)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct intel_pt_queue *ptq = data;
98462306a36Sopenharmony_ci	struct thread *thread;
98562306a36Sopenharmony_ci	struct addr_location al;
98662306a36Sopenharmony_ci	u8 cpumode;
98762306a36Sopenharmony_ci	u64 offset;
98862306a36Sopenharmony_ci	int res;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (ptq->state->to_nr) {
99162306a36Sopenharmony_ci		if (intel_pt_guest_kernel_ip(ip))
99262306a36Sopenharmony_ci			return intel_pt_match_pgd_ip(ptq->pt, ip, ip, NULL);
99362306a36Sopenharmony_ci		/* No support for decoding guest user space */
99462306a36Sopenharmony_ci		return -EINVAL;
99562306a36Sopenharmony_ci	} else if (ip >= ptq->pt->kernel_start) {
99662306a36Sopenharmony_ci		return intel_pt_match_pgd_ip(ptq->pt, ip, ip, NULL);
99762306a36Sopenharmony_ci	}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	cpumode = PERF_RECORD_MISC_USER;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	thread = ptq->thread;
100262306a36Sopenharmony_ci	if (!thread)
100362306a36Sopenharmony_ci		return -EINVAL;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	addr_location__init(&al);
100662306a36Sopenharmony_ci	if (!thread__find_map(thread, cpumode, ip, &al) || !map__dso(al.map))
100762306a36Sopenharmony_ci		return -EINVAL;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	offset = map__map_ip(al.map, ip);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	res = intel_pt_match_pgd_ip(ptq->pt, ip, offset, map__dso(al.map)->long_name);
101262306a36Sopenharmony_ci	addr_location__exit(&al);
101362306a36Sopenharmony_ci	return res;
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cistatic bool intel_pt_pgd_ip(uint64_t ip, void *data)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	return __intel_pt_pgd_ip(ip, data) > 0;
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic bool intel_pt_get_config(struct intel_pt *pt,
102262306a36Sopenharmony_ci				struct perf_event_attr *attr, u64 *config)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	if (attr->type == pt->pmu_type) {
102562306a36Sopenharmony_ci		if (config)
102662306a36Sopenharmony_ci			*config = attr->config;
102762306a36Sopenharmony_ci		return true;
102862306a36Sopenharmony_ci	}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return false;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistatic bool intel_pt_exclude_kernel(struct intel_pt *pt)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	struct evsel *evsel;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
103862306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, NULL) &&
103962306a36Sopenharmony_ci		    !evsel->core.attr.exclude_kernel)
104062306a36Sopenharmony_ci			return false;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci	return true;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic bool intel_pt_return_compression(struct intel_pt *pt)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct evsel *evsel;
104862306a36Sopenharmony_ci	u64 config;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	if (!pt->noretcomp_bit)
105162306a36Sopenharmony_ci		return true;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
105462306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config) &&
105562306a36Sopenharmony_ci		    (config & pt->noretcomp_bit))
105662306a36Sopenharmony_ci			return false;
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci	return true;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic bool intel_pt_branch_enable(struct intel_pt *pt)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	struct evsel *evsel;
106462306a36Sopenharmony_ci	u64 config;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
106762306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config) &&
106862306a36Sopenharmony_ci		    (config & INTEL_PT_CFG_PASS_THRU) &&
106962306a36Sopenharmony_ci		    !(config & INTEL_PT_CFG_BRANCH_EN))
107062306a36Sopenharmony_ci			return false;
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci	return true;
107362306a36Sopenharmony_ci}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic bool intel_pt_disabled_tnt(struct intel_pt *pt)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	struct evsel *evsel;
107862306a36Sopenharmony_ci	u64 config;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
108162306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config) &&
108262306a36Sopenharmony_ci		    config & INTEL_PT_CFG_TNT_DIS)
108362306a36Sopenharmony_ci			return true;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci	return false;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic unsigned int intel_pt_mtc_period(struct intel_pt *pt)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct evsel *evsel;
109162306a36Sopenharmony_ci	unsigned int shift;
109262306a36Sopenharmony_ci	u64 config;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (!pt->mtc_freq_bits)
109562306a36Sopenharmony_ci		return 0;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	for (shift = 0, config = pt->mtc_freq_bits; !(config & 1); shift++)
109862306a36Sopenharmony_ci		config >>= 1;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
110162306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config))
110262306a36Sopenharmony_ci			return (config & pt->mtc_freq_bits) >> shift;
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci	return 0;
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic bool intel_pt_timeless_decoding(struct intel_pt *pt)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	struct evsel *evsel;
111062306a36Sopenharmony_ci	bool timeless_decoding = true;
111162306a36Sopenharmony_ci	u64 config;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (!pt->tsc_bit || !pt->cap_user_time_zero || pt->synth_opts.timeless_decoding)
111462306a36Sopenharmony_ci		return true;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
111762306a36Sopenharmony_ci		if (!(evsel->core.attr.sample_type & PERF_SAMPLE_TIME))
111862306a36Sopenharmony_ci			return true;
111962306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config)) {
112062306a36Sopenharmony_ci			if (config & pt->tsc_bit)
112162306a36Sopenharmony_ci				timeless_decoding = false;
112262306a36Sopenharmony_ci			else
112362306a36Sopenharmony_ci				return true;
112462306a36Sopenharmony_ci		}
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci	return timeless_decoding;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic bool intel_pt_tracing_kernel(struct intel_pt *pt)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	struct evsel *evsel;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
113462306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, NULL) &&
113562306a36Sopenharmony_ci		    !evsel->core.attr.exclude_kernel)
113662306a36Sopenharmony_ci			return true;
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci	return false;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic bool intel_pt_have_tsc(struct intel_pt *pt)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct evsel *evsel;
114462306a36Sopenharmony_ci	bool have_tsc = false;
114562306a36Sopenharmony_ci	u64 config;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	if (!pt->tsc_bit)
114862306a36Sopenharmony_ci		return false;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
115162306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config)) {
115262306a36Sopenharmony_ci			if (config & pt->tsc_bit)
115362306a36Sopenharmony_ci				have_tsc = true;
115462306a36Sopenharmony_ci			else
115562306a36Sopenharmony_ci				return false;
115662306a36Sopenharmony_ci		}
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci	return have_tsc;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic bool intel_pt_have_mtc(struct intel_pt *pt)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	struct evsel *evsel;
116462306a36Sopenharmony_ci	u64 config;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
116762306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config) &&
116862306a36Sopenharmony_ci		    (config & pt->mtc_bit))
116962306a36Sopenharmony_ci			return true;
117062306a36Sopenharmony_ci	}
117162306a36Sopenharmony_ci	return false;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_cistatic bool intel_pt_sampling_mode(struct intel_pt *pt)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct evsel *evsel;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
117962306a36Sopenharmony_ci		if ((evsel->core.attr.sample_type & PERF_SAMPLE_AUX) &&
118062306a36Sopenharmony_ci		    evsel->core.attr.aux_sample_size)
118162306a36Sopenharmony_ci			return true;
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci	return false;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic u64 intel_pt_ctl(struct intel_pt *pt)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct evsel *evsel;
118962306a36Sopenharmony_ci	u64 config;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
119262306a36Sopenharmony_ci		if (intel_pt_get_config(pt, &evsel->core.attr, &config))
119362306a36Sopenharmony_ci			return config;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci	return 0;
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cistatic u64 intel_pt_ns_to_ticks(const struct intel_pt *pt, u64 ns)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	u64 quot, rem;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	quot = ns / pt->tc.time_mult;
120362306a36Sopenharmony_ci	rem  = ns % pt->tc.time_mult;
120462306a36Sopenharmony_ci	return (quot << pt->tc.time_shift) + (rem << pt->tc.time_shift) /
120562306a36Sopenharmony_ci		pt->tc.time_mult;
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic struct ip_callchain *intel_pt_alloc_chain(struct intel_pt *pt)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	size_t sz = sizeof(struct ip_callchain);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/* Add 1 to callchain_sz for callchain context */
121362306a36Sopenharmony_ci	sz += (pt->synth_opts.callchain_sz + 1) * sizeof(u64);
121462306a36Sopenharmony_ci	return zalloc(sz);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic int intel_pt_callchain_init(struct intel_pt *pt)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct evsel *evsel;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
122262306a36Sopenharmony_ci		if (!(evsel->core.attr.sample_type & PERF_SAMPLE_CALLCHAIN))
122362306a36Sopenharmony_ci			evsel->synth_sample_type |= PERF_SAMPLE_CALLCHAIN;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	pt->chain = intel_pt_alloc_chain(pt);
122762306a36Sopenharmony_ci	if (!pt->chain)
122862306a36Sopenharmony_ci		return -ENOMEM;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	return 0;
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistatic void intel_pt_add_callchain(struct intel_pt *pt,
123462306a36Sopenharmony_ci				   struct perf_sample *sample)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct thread *thread = machine__findnew_thread(pt->machine,
123762306a36Sopenharmony_ci							sample->pid,
123862306a36Sopenharmony_ci							sample->tid);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	thread_stack__sample_late(thread, sample->cpu, pt->chain,
124162306a36Sopenharmony_ci				  pt->synth_opts.callchain_sz + 1, sample->ip,
124262306a36Sopenharmony_ci				  pt->kernel_start);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	sample->callchain = pt->chain;
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_cistatic struct branch_stack *intel_pt_alloc_br_stack(unsigned int entry_cnt)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	size_t sz = sizeof(struct branch_stack);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	sz += entry_cnt * sizeof(struct branch_entry);
125262306a36Sopenharmony_ci	return zalloc(sz);
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic int intel_pt_br_stack_init(struct intel_pt *pt)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct evsel *evsel;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
126062306a36Sopenharmony_ci		if (!(evsel->core.attr.sample_type & PERF_SAMPLE_BRANCH_STACK))
126162306a36Sopenharmony_ci			evsel->synth_sample_type |= PERF_SAMPLE_BRANCH_STACK;
126262306a36Sopenharmony_ci	}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	pt->br_stack = intel_pt_alloc_br_stack(pt->br_stack_sz);
126562306a36Sopenharmony_ci	if (!pt->br_stack)
126662306a36Sopenharmony_ci		return -ENOMEM;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	return 0;
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic void intel_pt_add_br_stack(struct intel_pt *pt,
127262306a36Sopenharmony_ci				  struct perf_sample *sample)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	struct thread *thread = machine__findnew_thread(pt->machine,
127562306a36Sopenharmony_ci							sample->pid,
127662306a36Sopenharmony_ci							sample->tid);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	thread_stack__br_sample_late(thread, sample->cpu, pt->br_stack,
127962306a36Sopenharmony_ci				     pt->br_stack_sz, sample->ip,
128062306a36Sopenharmony_ci				     pt->kernel_start);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	sample->branch_stack = pt->br_stack;
128362306a36Sopenharmony_ci	thread__put(thread);
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci/* INTEL_PT_LBR_0, INTEL_PT_LBR_1 and INTEL_PT_LBR_2 */
128762306a36Sopenharmony_ci#define LBRS_MAX (INTEL_PT_BLK_ITEM_ID_CNT * 3U)
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_cistatic struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
129062306a36Sopenharmony_ci						   unsigned int queue_nr)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	struct intel_pt_params params = { .get_trace = 0, };
129362306a36Sopenharmony_ci	struct perf_env *env = pt->machine->env;
129462306a36Sopenharmony_ci	struct intel_pt_queue *ptq;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	ptq = zalloc(sizeof(struct intel_pt_queue));
129762306a36Sopenharmony_ci	if (!ptq)
129862306a36Sopenharmony_ci		return NULL;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	if (pt->synth_opts.callchain) {
130162306a36Sopenharmony_ci		ptq->chain = intel_pt_alloc_chain(pt);
130262306a36Sopenharmony_ci		if (!ptq->chain)
130362306a36Sopenharmony_ci			goto out_free;
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	if (pt->synth_opts.last_branch || pt->synth_opts.other_events) {
130762306a36Sopenharmony_ci		unsigned int entry_cnt = max(LBRS_MAX, pt->br_stack_sz);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci		ptq->last_branch = intel_pt_alloc_br_stack(entry_cnt);
131062306a36Sopenharmony_ci		if (!ptq->last_branch)
131162306a36Sopenharmony_ci			goto out_free;
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	ptq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
131562306a36Sopenharmony_ci	if (!ptq->event_buf)
131662306a36Sopenharmony_ci		goto out_free;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	ptq->pt = pt;
131962306a36Sopenharmony_ci	ptq->queue_nr = queue_nr;
132062306a36Sopenharmony_ci	ptq->exclude_kernel = intel_pt_exclude_kernel(pt);
132162306a36Sopenharmony_ci	ptq->pid = -1;
132262306a36Sopenharmony_ci	ptq->tid = -1;
132362306a36Sopenharmony_ci	ptq->cpu = -1;
132462306a36Sopenharmony_ci	ptq->next_tid = -1;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	params.get_trace = intel_pt_get_trace;
132762306a36Sopenharmony_ci	params.walk_insn = intel_pt_walk_next_insn;
132862306a36Sopenharmony_ci	params.lookahead = intel_pt_lookahead;
132962306a36Sopenharmony_ci	params.findnew_vmcs_info = intel_pt_findnew_vmcs_info;
133062306a36Sopenharmony_ci	params.data = ptq;
133162306a36Sopenharmony_ci	params.return_compression = intel_pt_return_compression(pt);
133262306a36Sopenharmony_ci	params.branch_enable = intel_pt_branch_enable(pt);
133362306a36Sopenharmony_ci	params.ctl = intel_pt_ctl(pt);
133462306a36Sopenharmony_ci	params.max_non_turbo_ratio = pt->max_non_turbo_ratio;
133562306a36Sopenharmony_ci	params.mtc_period = intel_pt_mtc_period(pt);
133662306a36Sopenharmony_ci	params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n;
133762306a36Sopenharmony_ci	params.tsc_ctc_ratio_d = pt->tsc_ctc_ratio_d;
133862306a36Sopenharmony_ci	params.quick = pt->synth_opts.quick;
133962306a36Sopenharmony_ci	params.vm_time_correlation = pt->synth_opts.vm_time_correlation;
134062306a36Sopenharmony_ci	params.vm_tm_corr_dry_run = pt->synth_opts.vm_tm_corr_dry_run;
134162306a36Sopenharmony_ci	params.first_timestamp = pt->first_timestamp;
134262306a36Sopenharmony_ci	params.max_loops = pt->max_loops;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	/* Cannot walk code without TNT, so force 'quick' mode */
134562306a36Sopenharmony_ci	if (params.branch_enable && intel_pt_disabled_tnt(pt) && !params.quick)
134662306a36Sopenharmony_ci		params.quick = 1;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	if (pt->filts.cnt > 0)
134962306a36Sopenharmony_ci		params.pgd_ip = intel_pt_pgd_ip;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	if (pt->synth_opts.instructions || pt->synth_opts.cycles) {
135262306a36Sopenharmony_ci		if (pt->synth_opts.period) {
135362306a36Sopenharmony_ci			switch (pt->synth_opts.period_type) {
135462306a36Sopenharmony_ci			case PERF_ITRACE_PERIOD_INSTRUCTIONS:
135562306a36Sopenharmony_ci				params.period_type =
135662306a36Sopenharmony_ci						INTEL_PT_PERIOD_INSTRUCTIONS;
135762306a36Sopenharmony_ci				params.period = pt->synth_opts.period;
135862306a36Sopenharmony_ci				break;
135962306a36Sopenharmony_ci			case PERF_ITRACE_PERIOD_TICKS:
136062306a36Sopenharmony_ci				params.period_type = INTEL_PT_PERIOD_TICKS;
136162306a36Sopenharmony_ci				params.period = pt->synth_opts.period;
136262306a36Sopenharmony_ci				break;
136362306a36Sopenharmony_ci			case PERF_ITRACE_PERIOD_NANOSECS:
136462306a36Sopenharmony_ci				params.period_type = INTEL_PT_PERIOD_TICKS;
136562306a36Sopenharmony_ci				params.period = intel_pt_ns_to_ticks(pt,
136662306a36Sopenharmony_ci							pt->synth_opts.period);
136762306a36Sopenharmony_ci				break;
136862306a36Sopenharmony_ci			default:
136962306a36Sopenharmony_ci				break;
137062306a36Sopenharmony_ci			}
137162306a36Sopenharmony_ci		}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci		if (!params.period) {
137462306a36Sopenharmony_ci			params.period_type = INTEL_PT_PERIOD_INSTRUCTIONS;
137562306a36Sopenharmony_ci			params.period = 1;
137662306a36Sopenharmony_ci		}
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (env->cpuid && !strncmp(env->cpuid, "GenuineIntel,6,92,", 18))
138062306a36Sopenharmony_ci		params.flags |= INTEL_PT_FUP_WITH_NLIP;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	ptq->decoder = intel_pt_decoder_new(&params);
138362306a36Sopenharmony_ci	if (!ptq->decoder)
138462306a36Sopenharmony_ci		goto out_free;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	return ptq;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ciout_free:
138962306a36Sopenharmony_ci	zfree(&ptq->event_buf);
139062306a36Sopenharmony_ci	zfree(&ptq->last_branch);
139162306a36Sopenharmony_ci	zfree(&ptq->chain);
139262306a36Sopenharmony_ci	free(ptq);
139362306a36Sopenharmony_ci	return NULL;
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic void intel_pt_free_queue(void *priv)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	struct intel_pt_queue *ptq = priv;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	if (!ptq)
140162306a36Sopenharmony_ci		return;
140262306a36Sopenharmony_ci	thread__zput(ptq->thread);
140362306a36Sopenharmony_ci	thread__zput(ptq->guest_thread);
140462306a36Sopenharmony_ci	thread__zput(ptq->unknown_guest_thread);
140562306a36Sopenharmony_ci	intel_pt_decoder_free(ptq->decoder);
140662306a36Sopenharmony_ci	zfree(&ptq->event_buf);
140762306a36Sopenharmony_ci	zfree(&ptq->last_branch);
140862306a36Sopenharmony_ci	zfree(&ptq->chain);
140962306a36Sopenharmony_ci	free(ptq);
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic void intel_pt_first_timestamp(struct intel_pt *pt, u64 timestamp)
141362306a36Sopenharmony_ci{
141462306a36Sopenharmony_ci	unsigned int i;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	pt->first_timestamp = timestamp;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	for (i = 0; i < pt->queues.nr_queues; i++) {
141962306a36Sopenharmony_ci		struct auxtrace_queue *queue = &pt->queues.queue_array[i];
142062306a36Sopenharmony_ci		struct intel_pt_queue *ptq = queue->priv;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci		if (ptq && ptq->decoder)
142362306a36Sopenharmony_ci			intel_pt_set_first_timestamp(ptq->decoder, timestamp);
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic int intel_pt_get_guest_from_sideband(struct intel_pt_queue *ptq)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	struct machines *machines = &ptq->pt->session->machines;
143062306a36Sopenharmony_ci	struct machine *machine;
143162306a36Sopenharmony_ci	pid_t machine_pid = ptq->pid;
143262306a36Sopenharmony_ci	pid_t tid;
143362306a36Sopenharmony_ci	int vcpu;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	if (machine_pid <= 0)
143662306a36Sopenharmony_ci		return 0; /* Not a guest machine */
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	machine = machines__find(machines, machine_pid);
143962306a36Sopenharmony_ci	if (!machine)
144062306a36Sopenharmony_ci		return 0; /* Not a guest machine */
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (ptq->guest_machine != machine) {
144362306a36Sopenharmony_ci		ptq->guest_machine = NULL;
144462306a36Sopenharmony_ci		thread__zput(ptq->guest_thread);
144562306a36Sopenharmony_ci		thread__zput(ptq->unknown_guest_thread);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci		ptq->unknown_guest_thread = machine__find_thread(machine, 0, 0);
144862306a36Sopenharmony_ci		if (!ptq->unknown_guest_thread)
144962306a36Sopenharmony_ci			return -1;
145062306a36Sopenharmony_ci		ptq->guest_machine = machine;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	vcpu = ptq->thread ? thread__guest_cpu(ptq->thread) : -1;
145462306a36Sopenharmony_ci	if (vcpu < 0)
145562306a36Sopenharmony_ci		return -1;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	tid = machine__get_current_tid(machine, vcpu);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	if (ptq->guest_thread && thread__tid(ptq->guest_thread) != tid)
146062306a36Sopenharmony_ci		thread__zput(ptq->guest_thread);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	if (!ptq->guest_thread) {
146362306a36Sopenharmony_ci		ptq->guest_thread = machine__find_thread(machine, -1, tid);
146462306a36Sopenharmony_ci		if (!ptq->guest_thread)
146562306a36Sopenharmony_ci			return -1;
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	ptq->guest_machine_pid = machine_pid;
146962306a36Sopenharmony_ci	ptq->guest_pid = thread__pid(ptq->guest_thread);
147062306a36Sopenharmony_ci	ptq->guest_tid = tid;
147162306a36Sopenharmony_ci	ptq->vcpu = vcpu;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	return 0;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_cistatic void intel_pt_set_pid_tid_cpu(struct intel_pt *pt,
147762306a36Sopenharmony_ci				     struct auxtrace_queue *queue)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	struct intel_pt_queue *ptq = queue->priv;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	if (queue->tid == -1 || pt->have_sched_switch) {
148262306a36Sopenharmony_ci		ptq->tid = machine__get_current_tid(pt->machine, ptq->cpu);
148362306a36Sopenharmony_ci		if (ptq->tid == -1)
148462306a36Sopenharmony_ci			ptq->pid = -1;
148562306a36Sopenharmony_ci		thread__zput(ptq->thread);
148662306a36Sopenharmony_ci	}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	if (!ptq->thread && ptq->tid != -1)
148962306a36Sopenharmony_ci		ptq->thread = machine__find_thread(pt->machine, -1, ptq->tid);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	if (ptq->thread) {
149262306a36Sopenharmony_ci		ptq->pid = thread__pid(ptq->thread);
149362306a36Sopenharmony_ci		if (queue->cpu == -1)
149462306a36Sopenharmony_ci			ptq->cpu = thread__cpu(ptq->thread);
149562306a36Sopenharmony_ci	}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (pt->have_guest_sideband && intel_pt_get_guest_from_sideband(ptq)) {
149862306a36Sopenharmony_ci		ptq->guest_machine_pid = 0;
149962306a36Sopenharmony_ci		ptq->guest_pid = -1;
150062306a36Sopenharmony_ci		ptq->guest_tid = -1;
150162306a36Sopenharmony_ci		ptq->vcpu = -1;
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_cistatic void intel_pt_sample_flags(struct intel_pt_queue *ptq)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	ptq->insn_len = 0;
151062306a36Sopenharmony_ci	if (ptq->state->flags & INTEL_PT_ABORT_TX) {
151162306a36Sopenharmony_ci		ptq->flags = PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT;
151262306a36Sopenharmony_ci	} else if (ptq->state->flags & INTEL_PT_ASYNC) {
151362306a36Sopenharmony_ci		if (!ptq->state->to_ip)
151462306a36Sopenharmony_ci			ptq->flags = PERF_IP_FLAG_BRANCH |
151562306a36Sopenharmony_ci				     PERF_IP_FLAG_ASYNC |
151662306a36Sopenharmony_ci				     PERF_IP_FLAG_TRACE_END;
151762306a36Sopenharmony_ci		else if (ptq->state->from_nr && !ptq->state->to_nr)
151862306a36Sopenharmony_ci			ptq->flags = PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |
151962306a36Sopenharmony_ci				     PERF_IP_FLAG_ASYNC |
152062306a36Sopenharmony_ci				     PERF_IP_FLAG_VMEXIT;
152162306a36Sopenharmony_ci		else
152262306a36Sopenharmony_ci			ptq->flags = PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |
152362306a36Sopenharmony_ci				     PERF_IP_FLAG_ASYNC |
152462306a36Sopenharmony_ci				     PERF_IP_FLAG_INTERRUPT;
152562306a36Sopenharmony_ci	} else {
152662306a36Sopenharmony_ci		if (ptq->state->from_ip)
152762306a36Sopenharmony_ci			ptq->flags = intel_pt_insn_type(ptq->state->insn_op);
152862306a36Sopenharmony_ci		else
152962306a36Sopenharmony_ci			ptq->flags = PERF_IP_FLAG_BRANCH |
153062306a36Sopenharmony_ci				     PERF_IP_FLAG_TRACE_BEGIN;
153162306a36Sopenharmony_ci		if (ptq->state->flags & INTEL_PT_IN_TX)
153262306a36Sopenharmony_ci			ptq->flags |= PERF_IP_FLAG_IN_TX;
153362306a36Sopenharmony_ci		ptq->insn_len = ptq->state->insn_len;
153462306a36Sopenharmony_ci		memcpy(ptq->insn, ptq->state->insn, INTEL_PT_INSN_BUF_SZ);
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	if (ptq->state->type & INTEL_PT_TRACE_BEGIN)
153862306a36Sopenharmony_ci		ptq->flags |= PERF_IP_FLAG_TRACE_BEGIN;
153962306a36Sopenharmony_ci	if (ptq->state->type & INTEL_PT_TRACE_END)
154062306a36Sopenharmony_ci		ptq->flags |= PERF_IP_FLAG_TRACE_END;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	if (pt->cap_event_trace) {
154362306a36Sopenharmony_ci		if (ptq->state->type & INTEL_PT_IFLAG_CHG) {
154462306a36Sopenharmony_ci			if (!ptq->state->from_iflag)
154562306a36Sopenharmony_ci				ptq->flags |= PERF_IP_FLAG_INTR_DISABLE;
154662306a36Sopenharmony_ci			if (ptq->state->from_iflag != ptq->state->to_iflag)
154762306a36Sopenharmony_ci				ptq->flags |= PERF_IP_FLAG_INTR_TOGGLE;
154862306a36Sopenharmony_ci		} else if (!ptq->state->to_iflag) {
154962306a36Sopenharmony_ci			ptq->flags |= PERF_IP_FLAG_INTR_DISABLE;
155062306a36Sopenharmony_ci		}
155162306a36Sopenharmony_ci	}
155262306a36Sopenharmony_ci}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_cistatic void intel_pt_setup_time_range(struct intel_pt *pt,
155562306a36Sopenharmony_ci				      struct intel_pt_queue *ptq)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	if (!pt->range_cnt)
155862306a36Sopenharmony_ci		return;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	ptq->sel_timestamp = pt->time_ranges[0].start;
156162306a36Sopenharmony_ci	ptq->sel_idx = 0;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (ptq->sel_timestamp) {
156462306a36Sopenharmony_ci		ptq->sel_start = true;
156562306a36Sopenharmony_ci	} else {
156662306a36Sopenharmony_ci		ptq->sel_timestamp = pt->time_ranges[0].end;
156762306a36Sopenharmony_ci		ptq->sel_start = false;
156862306a36Sopenharmony_ci	}
156962306a36Sopenharmony_ci}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic int intel_pt_setup_queue(struct intel_pt *pt,
157262306a36Sopenharmony_ci				struct auxtrace_queue *queue,
157362306a36Sopenharmony_ci				unsigned int queue_nr)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	struct intel_pt_queue *ptq = queue->priv;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	if (list_empty(&queue->head))
157862306a36Sopenharmony_ci		return 0;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (!ptq) {
158162306a36Sopenharmony_ci		ptq = intel_pt_alloc_queue(pt, queue_nr);
158262306a36Sopenharmony_ci		if (!ptq)
158362306a36Sopenharmony_ci			return -ENOMEM;
158462306a36Sopenharmony_ci		queue->priv = ptq;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci		if (queue->cpu != -1)
158762306a36Sopenharmony_ci			ptq->cpu = queue->cpu;
158862306a36Sopenharmony_ci		ptq->tid = queue->tid;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci		ptq->cbr_seen = UINT_MAX;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci		if (pt->sampling_mode && !pt->snapshot_mode &&
159362306a36Sopenharmony_ci		    pt->timeless_decoding)
159462306a36Sopenharmony_ci			ptq->step_through_buffers = true;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		ptq->sync_switch = pt->sync_switch;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		intel_pt_setup_time_range(pt, ptq);
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	if (!ptq->on_heap &&
160262306a36Sopenharmony_ci	    (!ptq->sync_switch ||
160362306a36Sopenharmony_ci	     ptq->switch_state != INTEL_PT_SS_EXPECTING_SWITCH_EVENT)) {
160462306a36Sopenharmony_ci		const struct intel_pt_state *state;
160562306a36Sopenharmony_ci		int ret;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci		if (pt->timeless_decoding)
160862306a36Sopenharmony_ci			return 0;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci		intel_pt_log("queue %u getting timestamp\n", queue_nr);
161162306a36Sopenharmony_ci		intel_pt_log("queue %u decoding cpu %d pid %d tid %d\n",
161262306a36Sopenharmony_ci			     queue_nr, ptq->cpu, ptq->pid, ptq->tid);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci		if (ptq->sel_start && ptq->sel_timestamp) {
161562306a36Sopenharmony_ci			ret = intel_pt_fast_forward(ptq->decoder,
161662306a36Sopenharmony_ci						    ptq->sel_timestamp);
161762306a36Sopenharmony_ci			if (ret)
161862306a36Sopenharmony_ci				return ret;
161962306a36Sopenharmony_ci		}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci		while (1) {
162262306a36Sopenharmony_ci			state = intel_pt_decode(ptq->decoder);
162362306a36Sopenharmony_ci			if (state->err) {
162462306a36Sopenharmony_ci				if (state->err == INTEL_PT_ERR_NODATA) {
162562306a36Sopenharmony_ci					intel_pt_log("queue %u has no timestamp\n",
162662306a36Sopenharmony_ci						     queue_nr);
162762306a36Sopenharmony_ci					return 0;
162862306a36Sopenharmony_ci				}
162962306a36Sopenharmony_ci				continue;
163062306a36Sopenharmony_ci			}
163162306a36Sopenharmony_ci			if (state->timestamp)
163262306a36Sopenharmony_ci				break;
163362306a36Sopenharmony_ci		}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci		ptq->timestamp = state->timestamp;
163662306a36Sopenharmony_ci		intel_pt_log("queue %u timestamp 0x%" PRIx64 "\n",
163762306a36Sopenharmony_ci			     queue_nr, ptq->timestamp);
163862306a36Sopenharmony_ci		ptq->state = state;
163962306a36Sopenharmony_ci		ptq->have_sample = true;
164062306a36Sopenharmony_ci		if (ptq->sel_start && ptq->sel_timestamp &&
164162306a36Sopenharmony_ci		    ptq->timestamp < ptq->sel_timestamp)
164262306a36Sopenharmony_ci			ptq->have_sample = false;
164362306a36Sopenharmony_ci		intel_pt_sample_flags(ptq);
164462306a36Sopenharmony_ci		ret = auxtrace_heap__add(&pt->heap, queue_nr, ptq->timestamp);
164562306a36Sopenharmony_ci		if (ret)
164662306a36Sopenharmony_ci			return ret;
164762306a36Sopenharmony_ci		ptq->on_heap = true;
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	return 0;
165162306a36Sopenharmony_ci}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_cistatic int intel_pt_setup_queues(struct intel_pt *pt)
165462306a36Sopenharmony_ci{
165562306a36Sopenharmony_ci	unsigned int i;
165662306a36Sopenharmony_ci	int ret;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	for (i = 0; i < pt->queues.nr_queues; i++) {
165962306a36Sopenharmony_ci		ret = intel_pt_setup_queue(pt, &pt->queues.queue_array[i], i);
166062306a36Sopenharmony_ci		if (ret)
166162306a36Sopenharmony_ci			return ret;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci	return 0;
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cistatic inline bool intel_pt_skip_event(struct intel_pt *pt)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	return pt->synth_opts.initial_skip &&
166962306a36Sopenharmony_ci	       pt->num_events++ < pt->synth_opts.initial_skip;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci/*
167362306a36Sopenharmony_ci * Cannot count CBR as skipped because it won't go away until cbr == cbr_seen.
167462306a36Sopenharmony_ci * Also ensure CBR is first non-skipped event by allowing for 4 more samples
167562306a36Sopenharmony_ci * from this decoder state.
167662306a36Sopenharmony_ci */
167762306a36Sopenharmony_cistatic inline bool intel_pt_skip_cbr_event(struct intel_pt *pt)
167862306a36Sopenharmony_ci{
167962306a36Sopenharmony_ci	return pt->synth_opts.initial_skip &&
168062306a36Sopenharmony_ci	       pt->num_events + 4 < pt->synth_opts.initial_skip;
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cistatic void intel_pt_prep_a_sample(struct intel_pt_queue *ptq,
168462306a36Sopenharmony_ci				   union perf_event *event,
168562306a36Sopenharmony_ci				   struct perf_sample *sample)
168662306a36Sopenharmony_ci{
168762306a36Sopenharmony_ci	event->sample.header.type = PERF_RECORD_SAMPLE;
168862306a36Sopenharmony_ci	event->sample.header.size = sizeof(struct perf_event_header);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	sample->pid = ptq->pid;
169162306a36Sopenharmony_ci	sample->tid = ptq->tid;
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	if (ptq->pt->have_guest_sideband) {
169462306a36Sopenharmony_ci		if ((ptq->state->from_ip && ptq->state->from_nr) ||
169562306a36Sopenharmony_ci		    (ptq->state->to_ip && ptq->state->to_nr)) {
169662306a36Sopenharmony_ci			sample->pid = ptq->guest_pid;
169762306a36Sopenharmony_ci			sample->tid = ptq->guest_tid;
169862306a36Sopenharmony_ci			sample->machine_pid = ptq->guest_machine_pid;
169962306a36Sopenharmony_ci			sample->vcpu = ptq->vcpu;
170062306a36Sopenharmony_ci		}
170162306a36Sopenharmony_ci	}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	sample->cpu = ptq->cpu;
170462306a36Sopenharmony_ci	sample->insn_len = ptq->insn_len;
170562306a36Sopenharmony_ci	memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic void intel_pt_prep_b_sample(struct intel_pt *pt,
170962306a36Sopenharmony_ci				   struct intel_pt_queue *ptq,
171062306a36Sopenharmony_ci				   union perf_event *event,
171162306a36Sopenharmony_ci				   struct perf_sample *sample)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	intel_pt_prep_a_sample(ptq, event, sample);
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	if (!pt->timeless_decoding)
171662306a36Sopenharmony_ci		sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc);
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	sample->ip = ptq->state->from_ip;
171962306a36Sopenharmony_ci	sample->addr = ptq->state->to_ip;
172062306a36Sopenharmony_ci	sample->cpumode = intel_pt_cpumode(ptq, sample->ip, sample->addr);
172162306a36Sopenharmony_ci	sample->period = 1;
172262306a36Sopenharmony_ci	sample->flags = ptq->flags;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	event->sample.header.misc = sample->cpumode;
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistatic int intel_pt_inject_event(union perf_event *event,
172862306a36Sopenharmony_ci				 struct perf_sample *sample, u64 type)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	event->header.size = perf_event__sample_event_size(sample, type, 0);
173162306a36Sopenharmony_ci	return perf_event__synthesize_sample(event, type, 0, sample);
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_cistatic inline int intel_pt_opt_inject(struct intel_pt *pt,
173562306a36Sopenharmony_ci				      union perf_event *event,
173662306a36Sopenharmony_ci				      struct perf_sample *sample, u64 type)
173762306a36Sopenharmony_ci{
173862306a36Sopenharmony_ci	if (!pt->synth_opts.inject)
173962306a36Sopenharmony_ci		return 0;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	return intel_pt_inject_event(event, sample, type);
174262306a36Sopenharmony_ci}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_cistatic int intel_pt_deliver_synth_event(struct intel_pt *pt,
174562306a36Sopenharmony_ci					union perf_event *event,
174662306a36Sopenharmony_ci					struct perf_sample *sample, u64 type)
174762306a36Sopenharmony_ci{
174862306a36Sopenharmony_ci	int ret;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	ret = intel_pt_opt_inject(pt, event, sample, type);
175162306a36Sopenharmony_ci	if (ret)
175262306a36Sopenharmony_ci		return ret;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	ret = perf_session__deliver_synth_event(pt->session, event, sample);
175562306a36Sopenharmony_ci	if (ret)
175662306a36Sopenharmony_ci		pr_err("Intel PT: failed to deliver event, error %d\n", ret);
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	return ret;
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_cistatic int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq)
176262306a36Sopenharmony_ci{
176362306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
176462306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
176562306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
176662306a36Sopenharmony_ci	struct dummy_branch_stack {
176762306a36Sopenharmony_ci		u64			nr;
176862306a36Sopenharmony_ci		u64			hw_idx;
176962306a36Sopenharmony_ci		struct branch_entry	entries;
177062306a36Sopenharmony_ci	} dummy_bs;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	if (pt->branches_filter && !(pt->branches_filter & ptq->flags))
177362306a36Sopenharmony_ci		return 0;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
177662306a36Sopenharmony_ci		return 0;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	intel_pt_prep_b_sample(pt, ptq, event, &sample);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	sample.id = ptq->pt->branches_id;
178162306a36Sopenharmony_ci	sample.stream_id = ptq->pt->branches_id;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/*
178462306a36Sopenharmony_ci	 * perf report cannot handle events without a branch stack when using
178562306a36Sopenharmony_ci	 * SORT_MODE__BRANCH so make a dummy one.
178662306a36Sopenharmony_ci	 */
178762306a36Sopenharmony_ci	if (pt->synth_opts.last_branch && sort__mode == SORT_MODE__BRANCH) {
178862306a36Sopenharmony_ci		dummy_bs = (struct dummy_branch_stack){
178962306a36Sopenharmony_ci			.nr = 1,
179062306a36Sopenharmony_ci			.hw_idx = -1ULL,
179162306a36Sopenharmony_ci			.entries = {
179262306a36Sopenharmony_ci				.from = sample.ip,
179362306a36Sopenharmony_ci				.to = sample.addr,
179462306a36Sopenharmony_ci			},
179562306a36Sopenharmony_ci		};
179662306a36Sopenharmony_ci		sample.branch_stack = (struct branch_stack *)&dummy_bs;
179762306a36Sopenharmony_ci	}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	if (ptq->sample_ipc)
180062306a36Sopenharmony_ci		sample.cyc_cnt = ptq->ipc_cyc_cnt - ptq->last_br_cyc_cnt;
180162306a36Sopenharmony_ci	if (sample.cyc_cnt) {
180262306a36Sopenharmony_ci		sample.insn_cnt = ptq->ipc_insn_cnt - ptq->last_br_insn_cnt;
180362306a36Sopenharmony_ci		ptq->last_br_insn_cnt = ptq->ipc_insn_cnt;
180462306a36Sopenharmony_ci		ptq->last_br_cyc_cnt = ptq->ipc_cyc_cnt;
180562306a36Sopenharmony_ci	}
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
180862306a36Sopenharmony_ci					    pt->branches_sample_type);
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_cistatic void intel_pt_prep_sample(struct intel_pt *pt,
181262306a36Sopenharmony_ci				 struct intel_pt_queue *ptq,
181362306a36Sopenharmony_ci				 union perf_event *event,
181462306a36Sopenharmony_ci				 struct perf_sample *sample)
181562306a36Sopenharmony_ci{
181662306a36Sopenharmony_ci	intel_pt_prep_b_sample(pt, ptq, event, sample);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (pt->synth_opts.callchain) {
181962306a36Sopenharmony_ci		thread_stack__sample(ptq->thread, ptq->cpu, ptq->chain,
182062306a36Sopenharmony_ci				     pt->synth_opts.callchain_sz + 1,
182162306a36Sopenharmony_ci				     sample->ip, pt->kernel_start);
182262306a36Sopenharmony_ci		sample->callchain = ptq->chain;
182362306a36Sopenharmony_ci	}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	if (pt->synth_opts.last_branch) {
182662306a36Sopenharmony_ci		thread_stack__br_sample(ptq->thread, ptq->cpu, ptq->last_branch,
182762306a36Sopenharmony_ci					pt->br_stack_sz);
182862306a36Sopenharmony_ci		sample->branch_stack = ptq->last_branch;
182962306a36Sopenharmony_ci	}
183062306a36Sopenharmony_ci}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_cistatic int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq)
183362306a36Sopenharmony_ci{
183462306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
183562306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
183662306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
183962306a36Sopenharmony_ci		return 0;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	intel_pt_prep_sample(pt, ptq, event, &sample);
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	sample.id = ptq->pt->instructions_id;
184462306a36Sopenharmony_ci	sample.stream_id = ptq->pt->instructions_id;
184562306a36Sopenharmony_ci	if (pt->synth_opts.quick)
184662306a36Sopenharmony_ci		sample.period = 1;
184762306a36Sopenharmony_ci	else
184862306a36Sopenharmony_ci		sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	if (ptq->sample_ipc)
185162306a36Sopenharmony_ci		sample.cyc_cnt = ptq->ipc_cyc_cnt - ptq->last_in_cyc_cnt;
185262306a36Sopenharmony_ci	if (sample.cyc_cnt) {
185362306a36Sopenharmony_ci		sample.insn_cnt = ptq->ipc_insn_cnt - ptq->last_in_insn_cnt;
185462306a36Sopenharmony_ci		ptq->last_in_insn_cnt = ptq->ipc_insn_cnt;
185562306a36Sopenharmony_ci		ptq->last_in_cyc_cnt = ptq->ipc_cyc_cnt;
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	ptq->last_insn_cnt = ptq->state->tot_insn_cnt;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
186162306a36Sopenharmony_ci					    pt->instructions_sample_type);
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_cistatic int intel_pt_synth_cycle_sample(struct intel_pt_queue *ptq)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
186762306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
186862306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
186962306a36Sopenharmony_ci	u64 period = 0;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (ptq->sample_ipc)
187262306a36Sopenharmony_ci		period = ptq->ipc_cyc_cnt - ptq->last_cy_cyc_cnt;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	if (!period || intel_pt_skip_event(pt))
187562306a36Sopenharmony_ci		return 0;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	intel_pt_prep_sample(pt, ptq, event, &sample);
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	sample.id = ptq->pt->cycles_id;
188062306a36Sopenharmony_ci	sample.stream_id = ptq->pt->cycles_id;
188162306a36Sopenharmony_ci	sample.period = period;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	sample.cyc_cnt = period;
188462306a36Sopenharmony_ci	sample.insn_cnt = ptq->ipc_insn_cnt - ptq->last_cy_insn_cnt;
188562306a36Sopenharmony_ci	ptq->last_cy_insn_cnt = ptq->ipc_insn_cnt;
188662306a36Sopenharmony_ci	ptq->last_cy_cyc_cnt = ptq->ipc_cyc_cnt;
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample, pt->cycles_sample_type);
188962306a36Sopenharmony_ci}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_cistatic int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq)
189262306a36Sopenharmony_ci{
189362306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
189462306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
189562306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
189862306a36Sopenharmony_ci		return 0;
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	intel_pt_prep_sample(pt, ptq, event, &sample);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	sample.id = ptq->pt->transactions_id;
190362306a36Sopenharmony_ci	sample.stream_id = ptq->pt->transactions_id;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
190662306a36Sopenharmony_ci					    pt->transactions_sample_type);
190762306a36Sopenharmony_ci}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_cistatic void intel_pt_prep_p_sample(struct intel_pt *pt,
191062306a36Sopenharmony_ci				   struct intel_pt_queue *ptq,
191162306a36Sopenharmony_ci				   union perf_event *event,
191262306a36Sopenharmony_ci				   struct perf_sample *sample)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci	intel_pt_prep_sample(pt, ptq, event, sample);
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	/*
191762306a36Sopenharmony_ci	 * Zero IP is used to mean "trace start" but that is not the case for
191862306a36Sopenharmony_ci	 * power or PTWRITE events with no IP, so clear the flags.
191962306a36Sopenharmony_ci	 */
192062306a36Sopenharmony_ci	if (!sample->ip)
192162306a36Sopenharmony_ci		sample->flags = 0;
192262306a36Sopenharmony_ci}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_cistatic int intel_pt_synth_ptwrite_sample(struct intel_pt_queue *ptq)
192562306a36Sopenharmony_ci{
192662306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
192762306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
192862306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
192962306a36Sopenharmony_ci	struct perf_synth_intel_ptwrite raw;
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
193262306a36Sopenharmony_ci		return 0;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	sample.id = ptq->pt->ptwrites_id;
193762306a36Sopenharmony_ci	sample.stream_id = ptq->pt->ptwrites_id;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	raw.flags = 0;
194062306a36Sopenharmony_ci	raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP);
194162306a36Sopenharmony_ci	raw.payload = cpu_to_le64(ptq->state->ptw_payload);
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
194462306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
194762306a36Sopenharmony_ci					    pt->ptwrites_sample_type);
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cistatic int intel_pt_synth_cbr_sample(struct intel_pt_queue *ptq)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
195362306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
195462306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
195562306a36Sopenharmony_ci	struct perf_synth_intel_cbr raw;
195662306a36Sopenharmony_ci	u32 flags;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	if (intel_pt_skip_cbr_event(pt))
195962306a36Sopenharmony_ci		return 0;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	ptq->cbr_seen = ptq->state->cbr;
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	sample.id = ptq->pt->cbr_id;
196662306a36Sopenharmony_ci	sample.stream_id = ptq->pt->cbr_id;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	flags = (u16)ptq->state->cbr_payload | (pt->max_non_turbo_ratio << 16);
196962306a36Sopenharmony_ci	raw.flags = cpu_to_le32(flags);
197062306a36Sopenharmony_ci	raw.freq = cpu_to_le32(raw.cbr * pt->cbr2khz);
197162306a36Sopenharmony_ci	raw.reserved3 = 0;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
197462306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
197762306a36Sopenharmony_ci					    pt->pwr_events_sample_type);
197862306a36Sopenharmony_ci}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_cistatic int intel_pt_synth_psb_sample(struct intel_pt_queue *ptq)
198162306a36Sopenharmony_ci{
198262306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
198362306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
198462306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
198562306a36Sopenharmony_ci	struct perf_synth_intel_psb raw;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
198862306a36Sopenharmony_ci		return 0;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	sample.id = ptq->pt->psb_id;
199362306a36Sopenharmony_ci	sample.stream_id = ptq->pt->psb_id;
199462306a36Sopenharmony_ci	sample.flags = 0;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	raw.reserved = 0;
199762306a36Sopenharmony_ci	raw.offset = ptq->state->psb_offset;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
200062306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
200362306a36Sopenharmony_ci					    pt->pwr_events_sample_type);
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_cistatic int intel_pt_synth_mwait_sample(struct intel_pt_queue *ptq)
200762306a36Sopenharmony_ci{
200862306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
200962306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
201062306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
201162306a36Sopenharmony_ci	struct perf_synth_intel_mwait raw;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
201462306a36Sopenharmony_ci		return 0;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	sample.id = ptq->pt->mwait_id;
201962306a36Sopenharmony_ci	sample.stream_id = ptq->pt->mwait_id;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	raw.reserved = 0;
202262306a36Sopenharmony_ci	raw.payload = cpu_to_le64(ptq->state->mwait_payload);
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
202562306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
202862306a36Sopenharmony_ci					    pt->pwr_events_sample_type);
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_cistatic int intel_pt_synth_pwre_sample(struct intel_pt_queue *ptq)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
203462306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
203562306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
203662306a36Sopenharmony_ci	struct perf_synth_intel_pwre raw;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
203962306a36Sopenharmony_ci		return 0;
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	sample.id = ptq->pt->pwre_id;
204462306a36Sopenharmony_ci	sample.stream_id = ptq->pt->pwre_id;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	raw.reserved = 0;
204762306a36Sopenharmony_ci	raw.payload = cpu_to_le64(ptq->state->pwre_payload);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
205062306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
205362306a36Sopenharmony_ci					    pt->pwr_events_sample_type);
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic int intel_pt_synth_exstop_sample(struct intel_pt_queue *ptq)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
205962306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
206062306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
206162306a36Sopenharmony_ci	struct perf_synth_intel_exstop raw;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
206462306a36Sopenharmony_ci		return 0;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	sample.id = ptq->pt->exstop_id;
206962306a36Sopenharmony_ci	sample.stream_id = ptq->pt->exstop_id;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	raw.flags = 0;
207262306a36Sopenharmony_ci	raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
207562306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
207862306a36Sopenharmony_ci					    pt->pwr_events_sample_type);
207962306a36Sopenharmony_ci}
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_cistatic int intel_pt_synth_pwrx_sample(struct intel_pt_queue *ptq)
208262306a36Sopenharmony_ci{
208362306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
208462306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
208562306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
208662306a36Sopenharmony_ci	struct perf_synth_intel_pwrx raw;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
208962306a36Sopenharmony_ci		return 0;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	sample.id = ptq->pt->pwrx_id;
209462306a36Sopenharmony_ci	sample.stream_id = ptq->pt->pwrx_id;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	raw.reserved = 0;
209762306a36Sopenharmony_ci	raw.payload = cpu_to_le64(ptq->state->pwrx_payload);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
210062306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
210362306a36Sopenharmony_ci					    pt->pwr_events_sample_type);
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci/*
210762306a36Sopenharmony_ci * PEBS gp_regs array indexes plus 1 so that 0 means not present. Refer
210862306a36Sopenharmony_ci * intel_pt_add_gp_regs().
210962306a36Sopenharmony_ci */
211062306a36Sopenharmony_cistatic const int pebs_gp_regs[] = {
211162306a36Sopenharmony_ci	[PERF_REG_X86_FLAGS]	= 1,
211262306a36Sopenharmony_ci	[PERF_REG_X86_IP]	= 2,
211362306a36Sopenharmony_ci	[PERF_REG_X86_AX]	= 3,
211462306a36Sopenharmony_ci	[PERF_REG_X86_CX]	= 4,
211562306a36Sopenharmony_ci	[PERF_REG_X86_DX]	= 5,
211662306a36Sopenharmony_ci	[PERF_REG_X86_BX]	= 6,
211762306a36Sopenharmony_ci	[PERF_REG_X86_SP]	= 7,
211862306a36Sopenharmony_ci	[PERF_REG_X86_BP]	= 8,
211962306a36Sopenharmony_ci	[PERF_REG_X86_SI]	= 9,
212062306a36Sopenharmony_ci	[PERF_REG_X86_DI]	= 10,
212162306a36Sopenharmony_ci	[PERF_REG_X86_R8]	= 11,
212262306a36Sopenharmony_ci	[PERF_REG_X86_R9]	= 12,
212362306a36Sopenharmony_ci	[PERF_REG_X86_R10]	= 13,
212462306a36Sopenharmony_ci	[PERF_REG_X86_R11]	= 14,
212562306a36Sopenharmony_ci	[PERF_REG_X86_R12]	= 15,
212662306a36Sopenharmony_ci	[PERF_REG_X86_R13]	= 16,
212762306a36Sopenharmony_ci	[PERF_REG_X86_R14]	= 17,
212862306a36Sopenharmony_ci	[PERF_REG_X86_R15]	= 18,
212962306a36Sopenharmony_ci};
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cistatic u64 *intel_pt_add_gp_regs(struct regs_dump *intr_regs, u64 *pos,
213262306a36Sopenharmony_ci				 const struct intel_pt_blk_items *items,
213362306a36Sopenharmony_ci				 u64 regs_mask)
213462306a36Sopenharmony_ci{
213562306a36Sopenharmony_ci	const u64 *gp_regs = items->val[INTEL_PT_GP_REGS_POS];
213662306a36Sopenharmony_ci	u32 mask = items->mask[INTEL_PT_GP_REGS_POS];
213762306a36Sopenharmony_ci	u32 bit;
213862306a36Sopenharmony_ci	int i;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	for (i = 0, bit = 1; i < PERF_REG_X86_64_MAX; i++, bit <<= 1) {
214162306a36Sopenharmony_ci		/* Get the PEBS gp_regs array index */
214262306a36Sopenharmony_ci		int n = pebs_gp_regs[i] - 1;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		if (n < 0)
214562306a36Sopenharmony_ci			continue;
214662306a36Sopenharmony_ci		/*
214762306a36Sopenharmony_ci		 * Add only registers that were requested (i.e. 'regs_mask') and
214862306a36Sopenharmony_ci		 * that were provided (i.e. 'mask'), and update the resulting
214962306a36Sopenharmony_ci		 * mask (i.e. 'intr_regs->mask') accordingly.
215062306a36Sopenharmony_ci		 */
215162306a36Sopenharmony_ci		if (mask & 1 << n && regs_mask & bit) {
215262306a36Sopenharmony_ci			intr_regs->mask |= bit;
215362306a36Sopenharmony_ci			*pos++ = gp_regs[n];
215462306a36Sopenharmony_ci		}
215562306a36Sopenharmony_ci	}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	return pos;
215862306a36Sopenharmony_ci}
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci#ifndef PERF_REG_X86_XMM0
216162306a36Sopenharmony_ci#define PERF_REG_X86_XMM0 32
216262306a36Sopenharmony_ci#endif
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_cistatic void intel_pt_add_xmm(struct regs_dump *intr_regs, u64 *pos,
216562306a36Sopenharmony_ci			     const struct intel_pt_blk_items *items,
216662306a36Sopenharmony_ci			     u64 regs_mask)
216762306a36Sopenharmony_ci{
216862306a36Sopenharmony_ci	u32 mask = items->has_xmm & (regs_mask >> PERF_REG_X86_XMM0);
216962306a36Sopenharmony_ci	const u64 *xmm = items->xmm;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	/*
217262306a36Sopenharmony_ci	 * If there are any XMM registers, then there should be all of them.
217362306a36Sopenharmony_ci	 * Nevertheless, follow the logic to add only registers that were
217462306a36Sopenharmony_ci	 * requested (i.e. 'regs_mask') and that were provided (i.e. 'mask'),
217562306a36Sopenharmony_ci	 * and update the resulting mask (i.e. 'intr_regs->mask') accordingly.
217662306a36Sopenharmony_ci	 */
217762306a36Sopenharmony_ci	intr_regs->mask |= (u64)mask << PERF_REG_X86_XMM0;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	for (; mask; mask >>= 1, xmm++) {
218062306a36Sopenharmony_ci		if (mask & 1)
218162306a36Sopenharmony_ci			*pos++ = *xmm;
218262306a36Sopenharmony_ci	}
218362306a36Sopenharmony_ci}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci#define LBR_INFO_MISPRED	(1ULL << 63)
218662306a36Sopenharmony_ci#define LBR_INFO_IN_TX		(1ULL << 62)
218762306a36Sopenharmony_ci#define LBR_INFO_ABORT		(1ULL << 61)
218862306a36Sopenharmony_ci#define LBR_INFO_CYCLES		0xffff
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci/* Refer kernel's intel_pmu_store_pebs_lbrs() */
219162306a36Sopenharmony_cistatic u64 intel_pt_lbr_flags(u64 info)
219262306a36Sopenharmony_ci{
219362306a36Sopenharmony_ci	union {
219462306a36Sopenharmony_ci		struct branch_flags flags;
219562306a36Sopenharmony_ci		u64 result;
219662306a36Sopenharmony_ci	} u;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	u.result	  = 0;
219962306a36Sopenharmony_ci	u.flags.mispred	  = !!(info & LBR_INFO_MISPRED);
220062306a36Sopenharmony_ci	u.flags.predicted = !(info & LBR_INFO_MISPRED);
220162306a36Sopenharmony_ci	u.flags.in_tx	  = !!(info & LBR_INFO_IN_TX);
220262306a36Sopenharmony_ci	u.flags.abort	  = !!(info & LBR_INFO_ABORT);
220362306a36Sopenharmony_ci	u.flags.cycles	  = info & LBR_INFO_CYCLES;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	return u.result;
220662306a36Sopenharmony_ci}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_cistatic void intel_pt_add_lbrs(struct branch_stack *br_stack,
220962306a36Sopenharmony_ci			      const struct intel_pt_blk_items *items)
221062306a36Sopenharmony_ci{
221162306a36Sopenharmony_ci	u64 *to;
221262306a36Sopenharmony_ci	int i;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	br_stack->nr = 0;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	to = &br_stack->entries[0].from;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	for (i = INTEL_PT_LBR_0_POS; i <= INTEL_PT_LBR_2_POS; i++) {
221962306a36Sopenharmony_ci		u32 mask = items->mask[i];
222062306a36Sopenharmony_ci		const u64 *from = items->val[i];
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci		for (; mask; mask >>= 3, from += 3) {
222362306a36Sopenharmony_ci			if ((mask & 7) == 7) {
222462306a36Sopenharmony_ci				*to++ = from[0];
222562306a36Sopenharmony_ci				*to++ = from[1];
222662306a36Sopenharmony_ci				*to++ = intel_pt_lbr_flags(from[2]);
222762306a36Sopenharmony_ci				br_stack->nr += 1;
222862306a36Sopenharmony_ci			}
222962306a36Sopenharmony_ci		}
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_cistatic int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evsel *evsel, u64 id)
223462306a36Sopenharmony_ci{
223562306a36Sopenharmony_ci	const struct intel_pt_blk_items *items = &ptq->state->items;
223662306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
223762306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
223862306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
223962306a36Sopenharmony_ci	u64 sample_type = evsel->core.attr.sample_type;
224062306a36Sopenharmony_ci	u8 cpumode;
224162306a36Sopenharmony_ci	u64 regs[8 * sizeof(sample.intr_regs.mask)];
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
224462306a36Sopenharmony_ci		return 0;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	intel_pt_prep_a_sample(ptq, event, &sample);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	sample.id = id;
224962306a36Sopenharmony_ci	sample.stream_id = id;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (!evsel->core.attr.freq)
225262306a36Sopenharmony_ci		sample.period = evsel->core.attr.sample_period;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	/* No support for non-zero CS base */
225562306a36Sopenharmony_ci	if (items->has_ip)
225662306a36Sopenharmony_ci		sample.ip = items->ip;
225762306a36Sopenharmony_ci	else if (items->has_rip)
225862306a36Sopenharmony_ci		sample.ip = items->rip;
225962306a36Sopenharmony_ci	else
226062306a36Sopenharmony_ci		sample.ip = ptq->state->from_ip;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	cpumode = intel_pt_cpumode(ptq, sample.ip, 0);
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci	event->sample.header.misc = cpumode | PERF_RECORD_MISC_EXACT_IP;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	sample.cpumode = cpumode;
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	if (sample_type & PERF_SAMPLE_TIME) {
226962306a36Sopenharmony_ci		u64 timestamp = 0;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci		if (items->has_timestamp)
227262306a36Sopenharmony_ci			timestamp = items->timestamp;
227362306a36Sopenharmony_ci		else if (!pt->timeless_decoding)
227462306a36Sopenharmony_ci			timestamp = ptq->timestamp;
227562306a36Sopenharmony_ci		if (timestamp)
227662306a36Sopenharmony_ci			sample.time = tsc_to_perf_time(timestamp, &pt->tc);
227762306a36Sopenharmony_ci	}
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	if (sample_type & PERF_SAMPLE_CALLCHAIN &&
228062306a36Sopenharmony_ci	    pt->synth_opts.callchain) {
228162306a36Sopenharmony_ci		thread_stack__sample(ptq->thread, ptq->cpu, ptq->chain,
228262306a36Sopenharmony_ci				     pt->synth_opts.callchain_sz, sample.ip,
228362306a36Sopenharmony_ci				     pt->kernel_start);
228462306a36Sopenharmony_ci		sample.callchain = ptq->chain;
228562306a36Sopenharmony_ci	}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	if (sample_type & PERF_SAMPLE_REGS_INTR &&
228862306a36Sopenharmony_ci	    (items->mask[INTEL_PT_GP_REGS_POS] ||
228962306a36Sopenharmony_ci	     items->mask[INTEL_PT_XMM_POS])) {
229062306a36Sopenharmony_ci		u64 regs_mask = evsel->core.attr.sample_regs_intr;
229162306a36Sopenharmony_ci		u64 *pos;
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci		sample.intr_regs.abi = items->is_32_bit ?
229462306a36Sopenharmony_ci				       PERF_SAMPLE_REGS_ABI_32 :
229562306a36Sopenharmony_ci				       PERF_SAMPLE_REGS_ABI_64;
229662306a36Sopenharmony_ci		sample.intr_regs.regs = regs;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci		pos = intel_pt_add_gp_regs(&sample.intr_regs, regs, items, regs_mask);
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci		intel_pt_add_xmm(&sample.intr_regs, pos, items, regs_mask);
230162306a36Sopenharmony_ci	}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
230462306a36Sopenharmony_ci		if (items->mask[INTEL_PT_LBR_0_POS] ||
230562306a36Sopenharmony_ci		    items->mask[INTEL_PT_LBR_1_POS] ||
230662306a36Sopenharmony_ci		    items->mask[INTEL_PT_LBR_2_POS]) {
230762306a36Sopenharmony_ci			intel_pt_add_lbrs(ptq->last_branch, items);
230862306a36Sopenharmony_ci		} else if (pt->synth_opts.last_branch) {
230962306a36Sopenharmony_ci			thread_stack__br_sample(ptq->thread, ptq->cpu,
231062306a36Sopenharmony_ci						ptq->last_branch,
231162306a36Sopenharmony_ci						pt->br_stack_sz);
231262306a36Sopenharmony_ci		} else {
231362306a36Sopenharmony_ci			ptq->last_branch->nr = 0;
231462306a36Sopenharmony_ci		}
231562306a36Sopenharmony_ci		sample.branch_stack = ptq->last_branch;
231662306a36Sopenharmony_ci	}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	if (sample_type & PERF_SAMPLE_ADDR && items->has_mem_access_address)
231962306a36Sopenharmony_ci		sample.addr = items->mem_access_address;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	if (sample_type & PERF_SAMPLE_WEIGHT_TYPE) {
232262306a36Sopenharmony_ci		/*
232362306a36Sopenharmony_ci		 * Refer kernel's setup_pebs_adaptive_sample_data() and
232462306a36Sopenharmony_ci		 * intel_hsw_weight().
232562306a36Sopenharmony_ci		 */
232662306a36Sopenharmony_ci		if (items->has_mem_access_latency) {
232762306a36Sopenharmony_ci			u64 weight = items->mem_access_latency >> 32;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci			/*
233062306a36Sopenharmony_ci			 * Starts from SPR, the mem access latency field
233162306a36Sopenharmony_ci			 * contains both cache latency [47:32] and instruction
233262306a36Sopenharmony_ci			 * latency [15:0]. The cache latency is the same as the
233362306a36Sopenharmony_ci			 * mem access latency on previous platforms.
233462306a36Sopenharmony_ci			 *
233562306a36Sopenharmony_ci			 * In practice, no memory access could last than 4G
233662306a36Sopenharmony_ci			 * cycles. Use latency >> 32 to distinguish the
233762306a36Sopenharmony_ci			 * different format of the mem access latency field.
233862306a36Sopenharmony_ci			 */
233962306a36Sopenharmony_ci			if (weight > 0) {
234062306a36Sopenharmony_ci				sample.weight = weight & 0xffff;
234162306a36Sopenharmony_ci				sample.ins_lat = items->mem_access_latency & 0xffff;
234262306a36Sopenharmony_ci			} else
234362306a36Sopenharmony_ci				sample.weight = items->mem_access_latency;
234462306a36Sopenharmony_ci		}
234562306a36Sopenharmony_ci		if (!sample.weight && items->has_tsx_aux_info) {
234662306a36Sopenharmony_ci			/* Cycles last block */
234762306a36Sopenharmony_ci			sample.weight = (u32)items->tsx_aux_info;
234862306a36Sopenharmony_ci		}
234962306a36Sopenharmony_ci	}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	if (sample_type & PERF_SAMPLE_TRANSACTION && items->has_tsx_aux_info) {
235262306a36Sopenharmony_ci		u64 ax = items->has_rax ? items->rax : 0;
235362306a36Sopenharmony_ci		/* Refer kernel's intel_hsw_transaction() */
235462306a36Sopenharmony_ci		u64 txn = (u8)(items->tsx_aux_info >> 32);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci		/* For RTM XABORTs also log the abort code from AX */
235762306a36Sopenharmony_ci		if (txn & PERF_TXN_TRANSACTION && ax & 1)
235862306a36Sopenharmony_ci			txn |= ((ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT;
235962306a36Sopenharmony_ci		sample.transaction = txn;
236062306a36Sopenharmony_ci	}
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample, sample_type);
236362306a36Sopenharmony_ci}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_cistatic int intel_pt_synth_single_pebs_sample(struct intel_pt_queue *ptq)
236662306a36Sopenharmony_ci{
236762306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
236862306a36Sopenharmony_ci	struct evsel *evsel = pt->pebs_evsel;
236962306a36Sopenharmony_ci	u64 id = evsel->core.id[0];
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	return intel_pt_do_synth_pebs_sample(ptq, evsel, id);
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_cistatic int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
237562306a36Sopenharmony_ci{
237662306a36Sopenharmony_ci	const struct intel_pt_blk_items *items = &ptq->state->items;
237762306a36Sopenharmony_ci	struct intel_pt_pebs_event *pe;
237862306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
237962306a36Sopenharmony_ci	int err = -EINVAL;
238062306a36Sopenharmony_ci	int hw_id;
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	if (!items->has_applicable_counters || !items->applicable_counters) {
238362306a36Sopenharmony_ci		if (!pt->single_pebs)
238462306a36Sopenharmony_ci			pr_err("PEBS-via-PT record with no applicable_counters\n");
238562306a36Sopenharmony_ci		return intel_pt_synth_single_pebs_sample(ptq);
238662306a36Sopenharmony_ci	}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	for_each_set_bit(hw_id, (unsigned long *)&items->applicable_counters, INTEL_PT_MAX_PEBS) {
238962306a36Sopenharmony_ci		pe = &ptq->pebs[hw_id];
239062306a36Sopenharmony_ci		if (!pe->evsel) {
239162306a36Sopenharmony_ci			if (!pt->single_pebs)
239262306a36Sopenharmony_ci				pr_err("PEBS-via-PT record with no matching event, hw_id %d\n",
239362306a36Sopenharmony_ci				       hw_id);
239462306a36Sopenharmony_ci			return intel_pt_synth_single_pebs_sample(ptq);
239562306a36Sopenharmony_ci		}
239662306a36Sopenharmony_ci		err = intel_pt_do_synth_pebs_sample(ptq, pe->evsel, pe->id);
239762306a36Sopenharmony_ci		if (err)
239862306a36Sopenharmony_ci			return err;
239962306a36Sopenharmony_ci	}
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	return err;
240262306a36Sopenharmony_ci}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_cistatic int intel_pt_synth_events_sample(struct intel_pt_queue *ptq)
240562306a36Sopenharmony_ci{
240662306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
240762306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
240862306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
240962306a36Sopenharmony_ci	struct {
241062306a36Sopenharmony_ci		struct perf_synth_intel_evt cfe;
241162306a36Sopenharmony_ci		struct perf_synth_intel_evd evd[INTEL_PT_MAX_EVDS];
241262306a36Sopenharmony_ci	} raw;
241362306a36Sopenharmony_ci	int i;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
241662306a36Sopenharmony_ci		return 0;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci	sample.id        = ptq->pt->evt_id;
242162306a36Sopenharmony_ci	sample.stream_id = ptq->pt->evt_id;
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	raw.cfe.type     = ptq->state->cfe_type;
242462306a36Sopenharmony_ci	raw.cfe.reserved = 0;
242562306a36Sopenharmony_ci	raw.cfe.ip       = !!(ptq->state->flags & INTEL_PT_FUP_IP);
242662306a36Sopenharmony_ci	raw.cfe.vector   = ptq->state->cfe_vector;
242762306a36Sopenharmony_ci	raw.cfe.evd_cnt  = ptq->state->evd_cnt;
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	for (i = 0; i < ptq->state->evd_cnt; i++) {
243062306a36Sopenharmony_ci		raw.evd[i].et       = 0;
243162306a36Sopenharmony_ci		raw.evd[i].evd_type = ptq->state->evd[i].type;
243262306a36Sopenharmony_ci		raw.evd[i].payload  = ptq->state->evd[i].payload;
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw) +
243662306a36Sopenharmony_ci			  ptq->state->evd_cnt * sizeof(struct perf_synth_intel_evd);
243762306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
244062306a36Sopenharmony_ci					    pt->evt_sample_type);
244162306a36Sopenharmony_ci}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_cistatic int intel_pt_synth_iflag_chg_sample(struct intel_pt_queue *ptq)
244462306a36Sopenharmony_ci{
244562306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
244662306a36Sopenharmony_ci	union perf_event *event = ptq->event_buf;
244762306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
244862306a36Sopenharmony_ci	struct perf_synth_intel_iflag_chg raw;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	if (intel_pt_skip_event(pt))
245162306a36Sopenharmony_ci		return 0;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	intel_pt_prep_p_sample(pt, ptq, event, &sample);
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	sample.id = ptq->pt->iflag_chg_id;
245662306a36Sopenharmony_ci	sample.stream_id = ptq->pt->iflag_chg_id;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	raw.flags = 0;
245962306a36Sopenharmony_ci	raw.iflag = ptq->state->to_iflag;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	if (ptq->state->type & INTEL_PT_BRANCH) {
246262306a36Sopenharmony_ci		raw.via_branch = 1;
246362306a36Sopenharmony_ci		raw.branch_ip = ptq->state->to_ip;
246462306a36Sopenharmony_ci	} else {
246562306a36Sopenharmony_ci		sample.addr = 0;
246662306a36Sopenharmony_ci	}
246762306a36Sopenharmony_ci	sample.flags = ptq->flags;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	sample.raw_size = perf_synth__raw_size(raw);
247062306a36Sopenharmony_ci	sample.raw_data = perf_synth__raw_data(&raw);
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	return intel_pt_deliver_synth_event(pt, event, &sample,
247362306a36Sopenharmony_ci					    pt->iflag_chg_sample_type);
247462306a36Sopenharmony_ci}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_cistatic int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu,
247762306a36Sopenharmony_ci				pid_t pid, pid_t tid, u64 ip, u64 timestamp,
247862306a36Sopenharmony_ci				pid_t machine_pid, int vcpu)
247962306a36Sopenharmony_ci{
248062306a36Sopenharmony_ci	bool dump_log_on_error = pt->synth_opts.log_plus_flags & AUXTRACE_LOG_FLG_ON_ERROR;
248162306a36Sopenharmony_ci	bool log_on_stdout = pt->synth_opts.log_plus_flags & AUXTRACE_LOG_FLG_USE_STDOUT;
248262306a36Sopenharmony_ci	union perf_event event;
248362306a36Sopenharmony_ci	char msg[MAX_AUXTRACE_ERROR_MSG];
248462306a36Sopenharmony_ci	int err;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	if (pt->synth_opts.error_minus_flags) {
248762306a36Sopenharmony_ci		if (code == INTEL_PT_ERR_OVR &&
248862306a36Sopenharmony_ci		    pt->synth_opts.error_minus_flags & AUXTRACE_ERR_FLG_OVERFLOW)
248962306a36Sopenharmony_ci			return 0;
249062306a36Sopenharmony_ci		if (code == INTEL_PT_ERR_LOST &&
249162306a36Sopenharmony_ci		    pt->synth_opts.error_minus_flags & AUXTRACE_ERR_FLG_DATA_LOST)
249262306a36Sopenharmony_ci			return 0;
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	intel_pt__strerror(code, msg, MAX_AUXTRACE_ERROR_MSG);
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	auxtrace_synth_guest_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
249862306a36Sopenharmony_ci				   code, cpu, pid, tid, ip, msg, timestamp,
249962306a36Sopenharmony_ci				   machine_pid, vcpu);
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	if (intel_pt_enable_logging && !log_on_stdout) {
250262306a36Sopenharmony_ci		FILE *fp = intel_pt_log_fp();
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci		if (fp)
250562306a36Sopenharmony_ci			perf_event__fprintf_auxtrace_error(&event, fp);
250662306a36Sopenharmony_ci	}
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	if (code != INTEL_PT_ERR_LOST && dump_log_on_error)
250962306a36Sopenharmony_ci		intel_pt_log_dump_buf();
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	err = perf_session__deliver_synth_event(pt->session, &event, NULL);
251262306a36Sopenharmony_ci	if (err)
251362306a36Sopenharmony_ci		pr_err("Intel Processor Trace: failed to deliver error event, error %d\n",
251462306a36Sopenharmony_ci		       err);
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	return err;
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_cistatic int intel_ptq_synth_error(struct intel_pt_queue *ptq,
252062306a36Sopenharmony_ci				 const struct intel_pt_state *state)
252162306a36Sopenharmony_ci{
252262306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
252362306a36Sopenharmony_ci	u64 tm = ptq->timestamp;
252462306a36Sopenharmony_ci	pid_t machine_pid = 0;
252562306a36Sopenharmony_ci	pid_t pid = ptq->pid;
252662306a36Sopenharmony_ci	pid_t tid = ptq->tid;
252762306a36Sopenharmony_ci	int vcpu = -1;
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	tm = pt->timeless_decoding ? 0 : tsc_to_perf_time(tm, &pt->tc);
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	if (pt->have_guest_sideband && state->from_nr) {
253262306a36Sopenharmony_ci		machine_pid = ptq->guest_machine_pid;
253362306a36Sopenharmony_ci		vcpu = ptq->vcpu;
253462306a36Sopenharmony_ci		pid = ptq->guest_pid;
253562306a36Sopenharmony_ci		tid = ptq->guest_tid;
253662306a36Sopenharmony_ci	}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	return intel_pt_synth_error(pt, state->err, ptq->cpu, pid, tid,
253962306a36Sopenharmony_ci				    state->from_ip, tm, machine_pid, vcpu);
254062306a36Sopenharmony_ci}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_cistatic int intel_pt_next_tid(struct intel_pt *pt, struct intel_pt_queue *ptq)
254362306a36Sopenharmony_ci{
254462306a36Sopenharmony_ci	struct auxtrace_queue *queue;
254562306a36Sopenharmony_ci	pid_t tid = ptq->next_tid;
254662306a36Sopenharmony_ci	int err;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	if (tid == -1)
254962306a36Sopenharmony_ci		return 0;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	intel_pt_log("switch: cpu %d tid %d\n", ptq->cpu, tid);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	err = machine__set_current_tid(pt->machine, ptq->cpu, -1, tid);
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	queue = &pt->queues.queue_array[ptq->queue_nr];
255662306a36Sopenharmony_ci	intel_pt_set_pid_tid_cpu(pt, queue);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	ptq->next_tid = -1;
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	return err;
256162306a36Sopenharmony_ci}
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_cistatic inline bool intel_pt_is_switch_ip(struct intel_pt_queue *ptq, u64 ip)
256462306a36Sopenharmony_ci{
256562306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	return ip == pt->switch_ip &&
256862306a36Sopenharmony_ci	       (ptq->flags & PERF_IP_FLAG_BRANCH) &&
256962306a36Sopenharmony_ci	       !(ptq->flags & (PERF_IP_FLAG_CONDITIONAL | PERF_IP_FLAG_ASYNC |
257062306a36Sopenharmony_ci			       PERF_IP_FLAG_INTERRUPT | PERF_IP_FLAG_TX_ABORT));
257162306a36Sopenharmony_ci}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci#define INTEL_PT_PWR_EVT (INTEL_PT_MWAIT_OP | INTEL_PT_PWR_ENTRY | \
257462306a36Sopenharmony_ci			  INTEL_PT_EX_STOP | INTEL_PT_PWR_EXIT)
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_cistatic int intel_pt_sample(struct intel_pt_queue *ptq)
257762306a36Sopenharmony_ci{
257862306a36Sopenharmony_ci	const struct intel_pt_state *state = ptq->state;
257962306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
258062306a36Sopenharmony_ci	int err;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	if (!ptq->have_sample)
258362306a36Sopenharmony_ci		return 0;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	ptq->have_sample = false;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	if (pt->synth_opts.approx_ipc) {
258862306a36Sopenharmony_ci		ptq->ipc_insn_cnt = ptq->state->tot_insn_cnt;
258962306a36Sopenharmony_ci		ptq->ipc_cyc_cnt = ptq->state->cycles;
259062306a36Sopenharmony_ci		ptq->sample_ipc = true;
259162306a36Sopenharmony_ci	} else {
259262306a36Sopenharmony_ci		ptq->ipc_insn_cnt = ptq->state->tot_insn_cnt;
259362306a36Sopenharmony_ci		ptq->ipc_cyc_cnt = ptq->state->tot_cyc_cnt;
259462306a36Sopenharmony_ci		ptq->sample_ipc = ptq->state->flags & INTEL_PT_SAMPLE_IPC;
259562306a36Sopenharmony_ci	}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	/* Ensure guest code maps are set up */
259862306a36Sopenharmony_ci	if (symbol_conf.guest_code && (state->from_nr || state->to_nr))
259962306a36Sopenharmony_ci		intel_pt_get_guest(ptq);
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	/*
260262306a36Sopenharmony_ci	 * Do PEBS first to allow for the possibility that the PEBS timestamp
260362306a36Sopenharmony_ci	 * precedes the current timestamp.
260462306a36Sopenharmony_ci	 */
260562306a36Sopenharmony_ci	if (pt->sample_pebs && state->type & INTEL_PT_BLK_ITEMS) {
260662306a36Sopenharmony_ci		err = intel_pt_synth_pebs_sample(ptq);
260762306a36Sopenharmony_ci		if (err)
260862306a36Sopenharmony_ci			return err;
260962306a36Sopenharmony_ci	}
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	if (pt->synth_opts.intr_events) {
261262306a36Sopenharmony_ci		if (state->type & INTEL_PT_EVT) {
261362306a36Sopenharmony_ci			err = intel_pt_synth_events_sample(ptq);
261462306a36Sopenharmony_ci			if (err)
261562306a36Sopenharmony_ci				return err;
261662306a36Sopenharmony_ci		}
261762306a36Sopenharmony_ci		if (state->type & INTEL_PT_IFLAG_CHG) {
261862306a36Sopenharmony_ci			err = intel_pt_synth_iflag_chg_sample(ptq);
261962306a36Sopenharmony_ci			if (err)
262062306a36Sopenharmony_ci				return err;
262162306a36Sopenharmony_ci		}
262262306a36Sopenharmony_ci	}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	if (pt->sample_pwr_events) {
262562306a36Sopenharmony_ci		if (state->type & INTEL_PT_PSB_EVT) {
262662306a36Sopenharmony_ci			err = intel_pt_synth_psb_sample(ptq);
262762306a36Sopenharmony_ci			if (err)
262862306a36Sopenharmony_ci				return err;
262962306a36Sopenharmony_ci		}
263062306a36Sopenharmony_ci		if (ptq->state->cbr != ptq->cbr_seen) {
263162306a36Sopenharmony_ci			err = intel_pt_synth_cbr_sample(ptq);
263262306a36Sopenharmony_ci			if (err)
263362306a36Sopenharmony_ci				return err;
263462306a36Sopenharmony_ci		}
263562306a36Sopenharmony_ci		if (state->type & INTEL_PT_PWR_EVT) {
263662306a36Sopenharmony_ci			if (state->type & INTEL_PT_MWAIT_OP) {
263762306a36Sopenharmony_ci				err = intel_pt_synth_mwait_sample(ptq);
263862306a36Sopenharmony_ci				if (err)
263962306a36Sopenharmony_ci					return err;
264062306a36Sopenharmony_ci			}
264162306a36Sopenharmony_ci			if (state->type & INTEL_PT_PWR_ENTRY) {
264262306a36Sopenharmony_ci				err = intel_pt_synth_pwre_sample(ptq);
264362306a36Sopenharmony_ci				if (err)
264462306a36Sopenharmony_ci					return err;
264562306a36Sopenharmony_ci			}
264662306a36Sopenharmony_ci			if (state->type & INTEL_PT_EX_STOP) {
264762306a36Sopenharmony_ci				err = intel_pt_synth_exstop_sample(ptq);
264862306a36Sopenharmony_ci				if (err)
264962306a36Sopenharmony_ci					return err;
265062306a36Sopenharmony_ci			}
265162306a36Sopenharmony_ci			if (state->type & INTEL_PT_PWR_EXIT) {
265262306a36Sopenharmony_ci				err = intel_pt_synth_pwrx_sample(ptq);
265362306a36Sopenharmony_ci				if (err)
265462306a36Sopenharmony_ci					return err;
265562306a36Sopenharmony_ci			}
265662306a36Sopenharmony_ci		}
265762306a36Sopenharmony_ci	}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	if (state->type & INTEL_PT_INSTRUCTION) {
266062306a36Sopenharmony_ci		if (pt->sample_instructions) {
266162306a36Sopenharmony_ci			err = intel_pt_synth_instruction_sample(ptq);
266262306a36Sopenharmony_ci			if (err)
266362306a36Sopenharmony_ci				return err;
266462306a36Sopenharmony_ci		}
266562306a36Sopenharmony_ci		if (pt->sample_cycles) {
266662306a36Sopenharmony_ci			err = intel_pt_synth_cycle_sample(ptq);
266762306a36Sopenharmony_ci			if (err)
266862306a36Sopenharmony_ci				return err;
266962306a36Sopenharmony_ci		}
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	if (pt->sample_transactions && (state->type & INTEL_PT_TRANSACTION)) {
267362306a36Sopenharmony_ci		err = intel_pt_synth_transaction_sample(ptq);
267462306a36Sopenharmony_ci		if (err)
267562306a36Sopenharmony_ci			return err;
267662306a36Sopenharmony_ci	}
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci	if (pt->sample_ptwrites && (state->type & INTEL_PT_PTW)) {
267962306a36Sopenharmony_ci		err = intel_pt_synth_ptwrite_sample(ptq);
268062306a36Sopenharmony_ci		if (err)
268162306a36Sopenharmony_ci			return err;
268262306a36Sopenharmony_ci	}
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	if (!(state->type & INTEL_PT_BRANCH))
268562306a36Sopenharmony_ci		return 0;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	if (pt->use_thread_stack) {
268862306a36Sopenharmony_ci		thread_stack__event(ptq->thread, ptq->cpu, ptq->flags,
268962306a36Sopenharmony_ci				    state->from_ip, state->to_ip, ptq->insn_len,
269062306a36Sopenharmony_ci				    state->trace_nr, pt->callstack,
269162306a36Sopenharmony_ci				    pt->br_stack_sz_plus,
269262306a36Sopenharmony_ci				    pt->mispred_all);
269362306a36Sopenharmony_ci	} else {
269462306a36Sopenharmony_ci		thread_stack__set_trace_nr(ptq->thread, ptq->cpu, state->trace_nr);
269562306a36Sopenharmony_ci	}
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	if (pt->sample_branches) {
269862306a36Sopenharmony_ci		if (state->from_nr != state->to_nr &&
269962306a36Sopenharmony_ci		    state->from_ip && state->to_ip) {
270062306a36Sopenharmony_ci			struct intel_pt_state *st = (struct intel_pt_state *)state;
270162306a36Sopenharmony_ci			u64 to_ip = st->to_ip;
270262306a36Sopenharmony_ci			u64 from_ip = st->from_ip;
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci			/*
270562306a36Sopenharmony_ci			 * perf cannot handle having different machines for ip
270662306a36Sopenharmony_ci			 * and addr, so create 2 branches.
270762306a36Sopenharmony_ci			 */
270862306a36Sopenharmony_ci			st->to_ip = 0;
270962306a36Sopenharmony_ci			err = intel_pt_synth_branch_sample(ptq);
271062306a36Sopenharmony_ci			if (err)
271162306a36Sopenharmony_ci				return err;
271262306a36Sopenharmony_ci			st->from_ip = 0;
271362306a36Sopenharmony_ci			st->to_ip = to_ip;
271462306a36Sopenharmony_ci			err = intel_pt_synth_branch_sample(ptq);
271562306a36Sopenharmony_ci			st->from_ip = from_ip;
271662306a36Sopenharmony_ci		} else {
271762306a36Sopenharmony_ci			err = intel_pt_synth_branch_sample(ptq);
271862306a36Sopenharmony_ci		}
271962306a36Sopenharmony_ci		if (err)
272062306a36Sopenharmony_ci			return err;
272162306a36Sopenharmony_ci	}
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (!ptq->sync_switch)
272462306a36Sopenharmony_ci		return 0;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	if (intel_pt_is_switch_ip(ptq, state->to_ip)) {
272762306a36Sopenharmony_ci		switch (ptq->switch_state) {
272862306a36Sopenharmony_ci		case INTEL_PT_SS_NOT_TRACING:
272962306a36Sopenharmony_ci		case INTEL_PT_SS_UNKNOWN:
273062306a36Sopenharmony_ci		case INTEL_PT_SS_EXPECTING_SWITCH_IP:
273162306a36Sopenharmony_ci			err = intel_pt_next_tid(pt, ptq);
273262306a36Sopenharmony_ci			if (err)
273362306a36Sopenharmony_ci				return err;
273462306a36Sopenharmony_ci			ptq->switch_state = INTEL_PT_SS_TRACING;
273562306a36Sopenharmony_ci			break;
273662306a36Sopenharmony_ci		default:
273762306a36Sopenharmony_ci			ptq->switch_state = INTEL_PT_SS_EXPECTING_SWITCH_EVENT;
273862306a36Sopenharmony_ci			return 1;
273962306a36Sopenharmony_ci		}
274062306a36Sopenharmony_ci	} else if (!state->to_ip) {
274162306a36Sopenharmony_ci		ptq->switch_state = INTEL_PT_SS_NOT_TRACING;
274262306a36Sopenharmony_ci	} else if (ptq->switch_state == INTEL_PT_SS_NOT_TRACING) {
274362306a36Sopenharmony_ci		ptq->switch_state = INTEL_PT_SS_UNKNOWN;
274462306a36Sopenharmony_ci	} else if (ptq->switch_state == INTEL_PT_SS_UNKNOWN &&
274562306a36Sopenharmony_ci		   state->to_ip == pt->ptss_ip &&
274662306a36Sopenharmony_ci		   (ptq->flags & PERF_IP_FLAG_CALL)) {
274762306a36Sopenharmony_ci		ptq->switch_state = INTEL_PT_SS_TRACING;
274862306a36Sopenharmony_ci	}
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	return 0;
275162306a36Sopenharmony_ci}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_cistatic u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
275462306a36Sopenharmony_ci{
275562306a36Sopenharmony_ci	struct machine *machine = pt->machine;
275662306a36Sopenharmony_ci	struct map *map;
275762306a36Sopenharmony_ci	struct symbol *sym, *start;
275862306a36Sopenharmony_ci	u64 ip, switch_ip = 0;
275962306a36Sopenharmony_ci	const char *ptss;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	if (ptss_ip)
276262306a36Sopenharmony_ci		*ptss_ip = 0;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	map = machine__kernel_map(machine);
276562306a36Sopenharmony_ci	if (!map)
276662306a36Sopenharmony_ci		return 0;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	if (map__load(map))
276962306a36Sopenharmony_ci		return 0;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	start = dso__first_symbol(map__dso(map));
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	for (sym = start; sym; sym = dso__next_symbol(sym)) {
277462306a36Sopenharmony_ci		if (sym->binding == STB_GLOBAL &&
277562306a36Sopenharmony_ci		    !strcmp(sym->name, "__switch_to")) {
277662306a36Sopenharmony_ci			ip = map__unmap_ip(map, sym->start);
277762306a36Sopenharmony_ci			if (ip >= map__start(map) && ip < map__end(map)) {
277862306a36Sopenharmony_ci				switch_ip = ip;
277962306a36Sopenharmony_ci				break;
278062306a36Sopenharmony_ci			}
278162306a36Sopenharmony_ci		}
278262306a36Sopenharmony_ci	}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	if (!switch_ip || !ptss_ip)
278562306a36Sopenharmony_ci		return 0;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	if (pt->have_sched_switch == 1)
278862306a36Sopenharmony_ci		ptss = "perf_trace_sched_switch";
278962306a36Sopenharmony_ci	else
279062306a36Sopenharmony_ci		ptss = "__perf_event_task_sched_out";
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	for (sym = start; sym; sym = dso__next_symbol(sym)) {
279362306a36Sopenharmony_ci		if (!strcmp(sym->name, ptss)) {
279462306a36Sopenharmony_ci			ip = map__unmap_ip(map, sym->start);
279562306a36Sopenharmony_ci			if (ip >= map__start(map) && ip < map__end(map)) {
279662306a36Sopenharmony_ci				*ptss_ip = ip;
279762306a36Sopenharmony_ci				break;
279862306a36Sopenharmony_ci			}
279962306a36Sopenharmony_ci		}
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	return switch_ip;
280362306a36Sopenharmony_ci}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_cistatic void intel_pt_enable_sync_switch(struct intel_pt *pt)
280662306a36Sopenharmony_ci{
280762306a36Sopenharmony_ci	unsigned int i;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	if (pt->sync_switch_not_supported)
281062306a36Sopenharmony_ci		return;
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	pt->sync_switch = true;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	for (i = 0; i < pt->queues.nr_queues; i++) {
281562306a36Sopenharmony_ci		struct auxtrace_queue *queue = &pt->queues.queue_array[i];
281662306a36Sopenharmony_ci		struct intel_pt_queue *ptq = queue->priv;
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci		if (ptq)
281962306a36Sopenharmony_ci			ptq->sync_switch = true;
282062306a36Sopenharmony_ci	}
282162306a36Sopenharmony_ci}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_cistatic void intel_pt_disable_sync_switch(struct intel_pt *pt)
282462306a36Sopenharmony_ci{
282562306a36Sopenharmony_ci	unsigned int i;
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	pt->sync_switch = false;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	for (i = 0; i < pt->queues.nr_queues; i++) {
283062306a36Sopenharmony_ci		struct auxtrace_queue *queue = &pt->queues.queue_array[i];
283162306a36Sopenharmony_ci		struct intel_pt_queue *ptq = queue->priv;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci		if (ptq) {
283462306a36Sopenharmony_ci			ptq->sync_switch = false;
283562306a36Sopenharmony_ci			intel_pt_next_tid(pt, ptq);
283662306a36Sopenharmony_ci		}
283762306a36Sopenharmony_ci	}
283862306a36Sopenharmony_ci}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci/*
284162306a36Sopenharmony_ci * To filter against time ranges, it is only necessary to look at the next start
284262306a36Sopenharmony_ci * or end time.
284362306a36Sopenharmony_ci */
284462306a36Sopenharmony_cistatic bool intel_pt_next_time(struct intel_pt_queue *ptq)
284562306a36Sopenharmony_ci{
284662306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	if (ptq->sel_start) {
284962306a36Sopenharmony_ci		/* Next time is an end time */
285062306a36Sopenharmony_ci		ptq->sel_start = false;
285162306a36Sopenharmony_ci		ptq->sel_timestamp = pt->time_ranges[ptq->sel_idx].end;
285262306a36Sopenharmony_ci		return true;
285362306a36Sopenharmony_ci	} else if (ptq->sel_idx + 1 < pt->range_cnt) {
285462306a36Sopenharmony_ci		/* Next time is a start time */
285562306a36Sopenharmony_ci		ptq->sel_start = true;
285662306a36Sopenharmony_ci		ptq->sel_idx += 1;
285762306a36Sopenharmony_ci		ptq->sel_timestamp = pt->time_ranges[ptq->sel_idx].start;
285862306a36Sopenharmony_ci		return true;
285962306a36Sopenharmony_ci	}
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	/* No next time */
286262306a36Sopenharmony_ci	return false;
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_cistatic int intel_pt_time_filter(struct intel_pt_queue *ptq, u64 *ff_timestamp)
286662306a36Sopenharmony_ci{
286762306a36Sopenharmony_ci	int err;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	while (1) {
287062306a36Sopenharmony_ci		if (ptq->sel_start) {
287162306a36Sopenharmony_ci			if (ptq->timestamp >= ptq->sel_timestamp) {
287262306a36Sopenharmony_ci				/* After start time, so consider next time */
287362306a36Sopenharmony_ci				intel_pt_next_time(ptq);
287462306a36Sopenharmony_ci				if (!ptq->sel_timestamp) {
287562306a36Sopenharmony_ci					/* No end time */
287662306a36Sopenharmony_ci					return 0;
287762306a36Sopenharmony_ci				}
287862306a36Sopenharmony_ci				/* Check against end time */
287962306a36Sopenharmony_ci				continue;
288062306a36Sopenharmony_ci			}
288162306a36Sopenharmony_ci			/* Before start time, so fast forward */
288262306a36Sopenharmony_ci			ptq->have_sample = false;
288362306a36Sopenharmony_ci			if (ptq->sel_timestamp > *ff_timestamp) {
288462306a36Sopenharmony_ci				if (ptq->sync_switch) {
288562306a36Sopenharmony_ci					intel_pt_next_tid(ptq->pt, ptq);
288662306a36Sopenharmony_ci					ptq->switch_state = INTEL_PT_SS_UNKNOWN;
288762306a36Sopenharmony_ci				}
288862306a36Sopenharmony_ci				*ff_timestamp = ptq->sel_timestamp;
288962306a36Sopenharmony_ci				err = intel_pt_fast_forward(ptq->decoder,
289062306a36Sopenharmony_ci							    ptq->sel_timestamp);
289162306a36Sopenharmony_ci				if (err)
289262306a36Sopenharmony_ci					return err;
289362306a36Sopenharmony_ci			}
289462306a36Sopenharmony_ci			return 0;
289562306a36Sopenharmony_ci		} else if (ptq->timestamp > ptq->sel_timestamp) {
289662306a36Sopenharmony_ci			/* After end time, so consider next time */
289762306a36Sopenharmony_ci			if (!intel_pt_next_time(ptq)) {
289862306a36Sopenharmony_ci				/* No next time range, so stop decoding */
289962306a36Sopenharmony_ci				ptq->have_sample = false;
290062306a36Sopenharmony_ci				ptq->switch_state = INTEL_PT_SS_NOT_TRACING;
290162306a36Sopenharmony_ci				return 1;
290262306a36Sopenharmony_ci			}
290362306a36Sopenharmony_ci			/* Check against next start time */
290462306a36Sopenharmony_ci			continue;
290562306a36Sopenharmony_ci		} else {
290662306a36Sopenharmony_ci			/* Before end time */
290762306a36Sopenharmony_ci			return 0;
290862306a36Sopenharmony_ci		}
290962306a36Sopenharmony_ci	}
291062306a36Sopenharmony_ci}
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_cistatic int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
291362306a36Sopenharmony_ci{
291462306a36Sopenharmony_ci	const struct intel_pt_state *state = ptq->state;
291562306a36Sopenharmony_ci	struct intel_pt *pt = ptq->pt;
291662306a36Sopenharmony_ci	u64 ff_timestamp = 0;
291762306a36Sopenharmony_ci	int err;
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	if (!pt->kernel_start) {
292062306a36Sopenharmony_ci		pt->kernel_start = machine__kernel_start(pt->machine);
292162306a36Sopenharmony_ci		if (pt->per_cpu_mmaps &&
292262306a36Sopenharmony_ci		    (pt->have_sched_switch == 1 || pt->have_sched_switch == 3) &&
292362306a36Sopenharmony_ci		    !pt->timeless_decoding && intel_pt_tracing_kernel(pt) &&
292462306a36Sopenharmony_ci		    !pt->sampling_mode && !pt->synth_opts.vm_time_correlation) {
292562306a36Sopenharmony_ci			pt->switch_ip = intel_pt_switch_ip(pt, &pt->ptss_ip);
292662306a36Sopenharmony_ci			if (pt->switch_ip) {
292762306a36Sopenharmony_ci				intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n",
292862306a36Sopenharmony_ci					     pt->switch_ip, pt->ptss_ip);
292962306a36Sopenharmony_ci				intel_pt_enable_sync_switch(pt);
293062306a36Sopenharmony_ci			}
293162306a36Sopenharmony_ci		}
293262306a36Sopenharmony_ci	}
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	intel_pt_log("queue %u decoding cpu %d pid %d tid %d\n",
293562306a36Sopenharmony_ci		     ptq->queue_nr, ptq->cpu, ptq->pid, ptq->tid);
293662306a36Sopenharmony_ci	while (1) {
293762306a36Sopenharmony_ci		err = intel_pt_sample(ptq);
293862306a36Sopenharmony_ci		if (err)
293962306a36Sopenharmony_ci			return err;
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci		state = intel_pt_decode(ptq->decoder);
294262306a36Sopenharmony_ci		if (state->err) {
294362306a36Sopenharmony_ci			if (state->err == INTEL_PT_ERR_NODATA)
294462306a36Sopenharmony_ci				return 1;
294562306a36Sopenharmony_ci			if (ptq->sync_switch &&
294662306a36Sopenharmony_ci			    state->from_ip >= pt->kernel_start) {
294762306a36Sopenharmony_ci				ptq->sync_switch = false;
294862306a36Sopenharmony_ci				intel_pt_next_tid(pt, ptq);
294962306a36Sopenharmony_ci			}
295062306a36Sopenharmony_ci			ptq->timestamp = state->est_timestamp;
295162306a36Sopenharmony_ci			if (pt->synth_opts.errors) {
295262306a36Sopenharmony_ci				err = intel_ptq_synth_error(ptq, state);
295362306a36Sopenharmony_ci				if (err)
295462306a36Sopenharmony_ci					return err;
295562306a36Sopenharmony_ci			}
295662306a36Sopenharmony_ci			continue;
295762306a36Sopenharmony_ci		}
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci		ptq->state = state;
296062306a36Sopenharmony_ci		ptq->have_sample = true;
296162306a36Sopenharmony_ci		intel_pt_sample_flags(ptq);
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci		/* Use estimated TSC upon return to user space */
296462306a36Sopenharmony_ci		if (pt->est_tsc &&
296562306a36Sopenharmony_ci		    (state->from_ip >= pt->kernel_start || !state->from_ip) &&
296662306a36Sopenharmony_ci		    state->to_ip && state->to_ip < pt->kernel_start) {
296762306a36Sopenharmony_ci			intel_pt_log("TSC %"PRIx64" est. TSC %"PRIx64"\n",
296862306a36Sopenharmony_ci				     state->timestamp, state->est_timestamp);
296962306a36Sopenharmony_ci			ptq->timestamp = state->est_timestamp;
297062306a36Sopenharmony_ci		/* Use estimated TSC in unknown switch state */
297162306a36Sopenharmony_ci		} else if (ptq->sync_switch &&
297262306a36Sopenharmony_ci			   ptq->switch_state == INTEL_PT_SS_UNKNOWN &&
297362306a36Sopenharmony_ci			   intel_pt_is_switch_ip(ptq, state->to_ip) &&
297462306a36Sopenharmony_ci			   ptq->next_tid == -1) {
297562306a36Sopenharmony_ci			intel_pt_log("TSC %"PRIx64" est. TSC %"PRIx64"\n",
297662306a36Sopenharmony_ci				     state->timestamp, state->est_timestamp);
297762306a36Sopenharmony_ci			ptq->timestamp = state->est_timestamp;
297862306a36Sopenharmony_ci		} else if (state->timestamp > ptq->timestamp) {
297962306a36Sopenharmony_ci			ptq->timestamp = state->timestamp;
298062306a36Sopenharmony_ci		}
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci		if (ptq->sel_timestamp) {
298362306a36Sopenharmony_ci			err = intel_pt_time_filter(ptq, &ff_timestamp);
298462306a36Sopenharmony_ci			if (err)
298562306a36Sopenharmony_ci				return err;
298662306a36Sopenharmony_ci		}
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci		if (!pt->timeless_decoding && ptq->timestamp >= *timestamp) {
298962306a36Sopenharmony_ci			*timestamp = ptq->timestamp;
299062306a36Sopenharmony_ci			return 0;
299162306a36Sopenharmony_ci		}
299262306a36Sopenharmony_ci	}
299362306a36Sopenharmony_ci	return 0;
299462306a36Sopenharmony_ci}
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_cistatic inline int intel_pt_update_queues(struct intel_pt *pt)
299762306a36Sopenharmony_ci{
299862306a36Sopenharmony_ci	if (pt->queues.new_data) {
299962306a36Sopenharmony_ci		pt->queues.new_data = false;
300062306a36Sopenharmony_ci		return intel_pt_setup_queues(pt);
300162306a36Sopenharmony_ci	}
300262306a36Sopenharmony_ci	return 0;
300362306a36Sopenharmony_ci}
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_cistatic int intel_pt_process_queues(struct intel_pt *pt, u64 timestamp)
300662306a36Sopenharmony_ci{
300762306a36Sopenharmony_ci	unsigned int queue_nr;
300862306a36Sopenharmony_ci	u64 ts;
300962306a36Sopenharmony_ci	int ret;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	while (1) {
301262306a36Sopenharmony_ci		struct auxtrace_queue *queue;
301362306a36Sopenharmony_ci		struct intel_pt_queue *ptq;
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci		if (!pt->heap.heap_cnt)
301662306a36Sopenharmony_ci			return 0;
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci		if (pt->heap.heap_array[0].ordinal >= timestamp)
301962306a36Sopenharmony_ci			return 0;
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci		queue_nr = pt->heap.heap_array[0].queue_nr;
302262306a36Sopenharmony_ci		queue = &pt->queues.queue_array[queue_nr];
302362306a36Sopenharmony_ci		ptq = queue->priv;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci		intel_pt_log("queue %u processing 0x%" PRIx64 " to 0x%" PRIx64 "\n",
302662306a36Sopenharmony_ci			     queue_nr, pt->heap.heap_array[0].ordinal,
302762306a36Sopenharmony_ci			     timestamp);
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci		auxtrace_heap__pop(&pt->heap);
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci		if (pt->heap.heap_cnt) {
303262306a36Sopenharmony_ci			ts = pt->heap.heap_array[0].ordinal + 1;
303362306a36Sopenharmony_ci			if (ts > timestamp)
303462306a36Sopenharmony_ci				ts = timestamp;
303562306a36Sopenharmony_ci		} else {
303662306a36Sopenharmony_ci			ts = timestamp;
303762306a36Sopenharmony_ci		}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci		intel_pt_set_pid_tid_cpu(pt, queue);
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_ci		ret = intel_pt_run_decoder(ptq, &ts);
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci		if (ret < 0) {
304462306a36Sopenharmony_ci			auxtrace_heap__add(&pt->heap, queue_nr, ts);
304562306a36Sopenharmony_ci			return ret;
304662306a36Sopenharmony_ci		}
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci		if (!ret) {
304962306a36Sopenharmony_ci			ret = auxtrace_heap__add(&pt->heap, queue_nr, ts);
305062306a36Sopenharmony_ci			if (ret < 0)
305162306a36Sopenharmony_ci				return ret;
305262306a36Sopenharmony_ci		} else {
305362306a36Sopenharmony_ci			ptq->on_heap = false;
305462306a36Sopenharmony_ci		}
305562306a36Sopenharmony_ci	}
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci	return 0;
305862306a36Sopenharmony_ci}
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_cistatic int intel_pt_process_timeless_queues(struct intel_pt *pt, pid_t tid,
306162306a36Sopenharmony_ci					    u64 time_)
306262306a36Sopenharmony_ci{
306362306a36Sopenharmony_ci	struct auxtrace_queues *queues = &pt->queues;
306462306a36Sopenharmony_ci	unsigned int i;
306562306a36Sopenharmony_ci	u64 ts = 0;
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
306862306a36Sopenharmony_ci		struct auxtrace_queue *queue = &pt->queues.queue_array[i];
306962306a36Sopenharmony_ci		struct intel_pt_queue *ptq = queue->priv;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci		if (ptq && (tid == -1 || ptq->tid == tid)) {
307262306a36Sopenharmony_ci			ptq->time = time_;
307362306a36Sopenharmony_ci			intel_pt_set_pid_tid_cpu(pt, queue);
307462306a36Sopenharmony_ci			intel_pt_run_decoder(ptq, &ts);
307562306a36Sopenharmony_ci		}
307662306a36Sopenharmony_ci	}
307762306a36Sopenharmony_ci	return 0;
307862306a36Sopenharmony_ci}
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_cistatic void intel_pt_sample_set_pid_tid_cpu(struct intel_pt_queue *ptq,
308162306a36Sopenharmony_ci					    struct auxtrace_queue *queue,
308262306a36Sopenharmony_ci					    struct perf_sample *sample)
308362306a36Sopenharmony_ci{
308462306a36Sopenharmony_ci	struct machine *m = ptq->pt->machine;
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	ptq->pid = sample->pid;
308762306a36Sopenharmony_ci	ptq->tid = sample->tid;
308862306a36Sopenharmony_ci	ptq->cpu = queue->cpu;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	intel_pt_log("queue %u cpu %d pid %d tid %d\n",
309162306a36Sopenharmony_ci		     ptq->queue_nr, ptq->cpu, ptq->pid, ptq->tid);
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	thread__zput(ptq->thread);
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	if (ptq->tid == -1)
309662306a36Sopenharmony_ci		return;
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	if (ptq->pid == -1) {
309962306a36Sopenharmony_ci		ptq->thread = machine__find_thread(m, -1, ptq->tid);
310062306a36Sopenharmony_ci		if (ptq->thread)
310162306a36Sopenharmony_ci			ptq->pid = thread__pid(ptq->thread);
310262306a36Sopenharmony_ci		return;
310362306a36Sopenharmony_ci	}
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	ptq->thread = machine__findnew_thread(m, ptq->pid, ptq->tid);
310662306a36Sopenharmony_ci}
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_cistatic int intel_pt_process_timeless_sample(struct intel_pt *pt,
310962306a36Sopenharmony_ci					    struct perf_sample *sample)
311062306a36Sopenharmony_ci{
311162306a36Sopenharmony_ci	struct auxtrace_queue *queue;
311262306a36Sopenharmony_ci	struct intel_pt_queue *ptq;
311362306a36Sopenharmony_ci	u64 ts = 0;
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	queue = auxtrace_queues__sample_queue(&pt->queues, sample, pt->session);
311662306a36Sopenharmony_ci	if (!queue)
311762306a36Sopenharmony_ci		return -EINVAL;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	ptq = queue->priv;
312062306a36Sopenharmony_ci	if (!ptq)
312162306a36Sopenharmony_ci		return 0;
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	ptq->stop = false;
312462306a36Sopenharmony_ci	ptq->time = sample->time;
312562306a36Sopenharmony_ci	intel_pt_sample_set_pid_tid_cpu(ptq, queue, sample);
312662306a36Sopenharmony_ci	intel_pt_run_decoder(ptq, &ts);
312762306a36Sopenharmony_ci	return 0;
312862306a36Sopenharmony_ci}
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_cistatic int intel_pt_lost(struct intel_pt *pt, struct perf_sample *sample)
313162306a36Sopenharmony_ci{
313262306a36Sopenharmony_ci	return intel_pt_synth_error(pt, INTEL_PT_ERR_LOST, sample->cpu,
313362306a36Sopenharmony_ci				    sample->pid, sample->tid, 0, sample->time,
313462306a36Sopenharmony_ci				    sample->machine_pid, sample->vcpu);
313562306a36Sopenharmony_ci}
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_cistatic struct intel_pt_queue *intel_pt_cpu_to_ptq(struct intel_pt *pt, int cpu)
313862306a36Sopenharmony_ci{
313962306a36Sopenharmony_ci	unsigned i, j;
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	if (cpu < 0 || !pt->queues.nr_queues)
314262306a36Sopenharmony_ci		return NULL;
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	if ((unsigned)cpu >= pt->queues.nr_queues)
314562306a36Sopenharmony_ci		i = pt->queues.nr_queues - 1;
314662306a36Sopenharmony_ci	else
314762306a36Sopenharmony_ci		i = cpu;
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	if (pt->queues.queue_array[i].cpu == cpu)
315062306a36Sopenharmony_ci		return pt->queues.queue_array[i].priv;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	for (j = 0; i > 0; j++) {
315362306a36Sopenharmony_ci		if (pt->queues.queue_array[--i].cpu == cpu)
315462306a36Sopenharmony_ci			return pt->queues.queue_array[i].priv;
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	for (; j < pt->queues.nr_queues; j++) {
315862306a36Sopenharmony_ci		if (pt->queues.queue_array[j].cpu == cpu)
315962306a36Sopenharmony_ci			return pt->queues.queue_array[j].priv;
316062306a36Sopenharmony_ci	}
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci	return NULL;
316362306a36Sopenharmony_ci}
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_cistatic int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid,
316662306a36Sopenharmony_ci				u64 timestamp)
316762306a36Sopenharmony_ci{
316862306a36Sopenharmony_ci	struct intel_pt_queue *ptq;
316962306a36Sopenharmony_ci	int err;
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	if (!pt->sync_switch)
317262306a36Sopenharmony_ci		return 1;
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	ptq = intel_pt_cpu_to_ptq(pt, cpu);
317562306a36Sopenharmony_ci	if (!ptq || !ptq->sync_switch)
317662306a36Sopenharmony_ci		return 1;
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	switch (ptq->switch_state) {
317962306a36Sopenharmony_ci	case INTEL_PT_SS_NOT_TRACING:
318062306a36Sopenharmony_ci		break;
318162306a36Sopenharmony_ci	case INTEL_PT_SS_UNKNOWN:
318262306a36Sopenharmony_ci	case INTEL_PT_SS_TRACING:
318362306a36Sopenharmony_ci		ptq->next_tid = tid;
318462306a36Sopenharmony_ci		ptq->switch_state = INTEL_PT_SS_EXPECTING_SWITCH_IP;
318562306a36Sopenharmony_ci		return 0;
318662306a36Sopenharmony_ci	case INTEL_PT_SS_EXPECTING_SWITCH_EVENT:
318762306a36Sopenharmony_ci		if (!ptq->on_heap) {
318862306a36Sopenharmony_ci			ptq->timestamp = perf_time_to_tsc(timestamp,
318962306a36Sopenharmony_ci							  &pt->tc);
319062306a36Sopenharmony_ci			err = auxtrace_heap__add(&pt->heap, ptq->queue_nr,
319162306a36Sopenharmony_ci						 ptq->timestamp);
319262306a36Sopenharmony_ci			if (err)
319362306a36Sopenharmony_ci				return err;
319462306a36Sopenharmony_ci			ptq->on_heap = true;
319562306a36Sopenharmony_ci		}
319662306a36Sopenharmony_ci		ptq->switch_state = INTEL_PT_SS_TRACING;
319762306a36Sopenharmony_ci		break;
319862306a36Sopenharmony_ci	case INTEL_PT_SS_EXPECTING_SWITCH_IP:
319962306a36Sopenharmony_ci		intel_pt_log("ERROR: cpu %d expecting switch ip\n", cpu);
320062306a36Sopenharmony_ci		break;
320162306a36Sopenharmony_ci	default:
320262306a36Sopenharmony_ci		break;
320362306a36Sopenharmony_ci	}
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	ptq->next_tid = -1;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	return 1;
320862306a36Sopenharmony_ci}
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
321162306a36Sopenharmony_cistatic int intel_pt_process_switch(struct intel_pt *pt,
321262306a36Sopenharmony_ci				   struct perf_sample *sample)
321362306a36Sopenharmony_ci{
321462306a36Sopenharmony_ci	pid_t tid;
321562306a36Sopenharmony_ci	int cpu, ret;
321662306a36Sopenharmony_ci	struct evsel *evsel = evlist__id2evsel(pt->session->evlist, sample->id);
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci	if (evsel != pt->switch_evsel)
321962306a36Sopenharmony_ci		return 0;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	tid = evsel__intval(evsel, sample, "next_pid");
322262306a36Sopenharmony_ci	cpu = sample->cpu;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
322562306a36Sopenharmony_ci		     cpu, tid, sample->time, perf_time_to_tsc(sample->time,
322662306a36Sopenharmony_ci		     &pt->tc));
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
322962306a36Sopenharmony_ci	if (ret <= 0)
323062306a36Sopenharmony_ci		return ret;
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	return machine__set_current_tid(pt->machine, cpu, -1, tid);
323362306a36Sopenharmony_ci}
323462306a36Sopenharmony_ci#endif /* HAVE_LIBTRACEEVENT */
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_cistatic int intel_pt_context_switch_in(struct intel_pt *pt,
323762306a36Sopenharmony_ci				      struct perf_sample *sample)
323862306a36Sopenharmony_ci{
323962306a36Sopenharmony_ci	pid_t pid = sample->pid;
324062306a36Sopenharmony_ci	pid_t tid = sample->tid;
324162306a36Sopenharmony_ci	int cpu = sample->cpu;
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_ci	if (pt->sync_switch) {
324462306a36Sopenharmony_ci		struct intel_pt_queue *ptq;
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci		ptq = intel_pt_cpu_to_ptq(pt, cpu);
324762306a36Sopenharmony_ci		if (ptq && ptq->sync_switch) {
324862306a36Sopenharmony_ci			ptq->next_tid = -1;
324962306a36Sopenharmony_ci			switch (ptq->switch_state) {
325062306a36Sopenharmony_ci			case INTEL_PT_SS_NOT_TRACING:
325162306a36Sopenharmony_ci			case INTEL_PT_SS_UNKNOWN:
325262306a36Sopenharmony_ci			case INTEL_PT_SS_TRACING:
325362306a36Sopenharmony_ci				break;
325462306a36Sopenharmony_ci			case INTEL_PT_SS_EXPECTING_SWITCH_EVENT:
325562306a36Sopenharmony_ci			case INTEL_PT_SS_EXPECTING_SWITCH_IP:
325662306a36Sopenharmony_ci				ptq->switch_state = INTEL_PT_SS_TRACING;
325762306a36Sopenharmony_ci				break;
325862306a36Sopenharmony_ci			default:
325962306a36Sopenharmony_ci				break;
326062306a36Sopenharmony_ci			}
326162306a36Sopenharmony_ci		}
326262306a36Sopenharmony_ci	}
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci	/*
326562306a36Sopenharmony_ci	 * If the current tid has not been updated yet, ensure it is now that
326662306a36Sopenharmony_ci	 * a "switch in" event has occurred.
326762306a36Sopenharmony_ci	 */
326862306a36Sopenharmony_ci	if (machine__get_current_tid(pt->machine, cpu) == tid)
326962306a36Sopenharmony_ci		return 0;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	return machine__set_current_tid(pt->machine, cpu, pid, tid);
327262306a36Sopenharmony_ci}
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_cistatic int intel_pt_guest_context_switch(struct intel_pt *pt,
327562306a36Sopenharmony_ci					 union perf_event *event,
327662306a36Sopenharmony_ci					 struct perf_sample *sample)
327762306a36Sopenharmony_ci{
327862306a36Sopenharmony_ci	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
327962306a36Sopenharmony_ci	struct machines *machines = &pt->session->machines;
328062306a36Sopenharmony_ci	struct machine *machine = machines__find(machines, sample->machine_pid);
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	pt->have_guest_sideband = true;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	/*
328562306a36Sopenharmony_ci	 * sync_switch cannot handle guest machines at present, so just disable
328662306a36Sopenharmony_ci	 * it.
328762306a36Sopenharmony_ci	 */
328862306a36Sopenharmony_ci	pt->sync_switch_not_supported = true;
328962306a36Sopenharmony_ci	if (pt->sync_switch)
329062306a36Sopenharmony_ci		intel_pt_disable_sync_switch(pt);
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	if (out)
329362306a36Sopenharmony_ci		return 0;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	if (!machine)
329662306a36Sopenharmony_ci		return -EINVAL;
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	return machine__set_current_tid(machine, sample->vcpu, sample->pid, sample->tid);
329962306a36Sopenharmony_ci}
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_cistatic int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event,
330262306a36Sopenharmony_ci				   struct perf_sample *sample)
330362306a36Sopenharmony_ci{
330462306a36Sopenharmony_ci	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
330562306a36Sopenharmony_ci	pid_t pid, tid;
330662306a36Sopenharmony_ci	int cpu, ret;
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	if (perf_event__is_guest(event))
330962306a36Sopenharmony_ci		return intel_pt_guest_context_switch(pt, event, sample);
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	cpu = sample->cpu;
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	if (pt->have_sched_switch == 3) {
331462306a36Sopenharmony_ci		if (!out)
331562306a36Sopenharmony_ci			return intel_pt_context_switch_in(pt, sample);
331662306a36Sopenharmony_ci		if (event->header.type != PERF_RECORD_SWITCH_CPU_WIDE) {
331762306a36Sopenharmony_ci			pr_err("Expecting CPU-wide context switch event\n");
331862306a36Sopenharmony_ci			return -EINVAL;
331962306a36Sopenharmony_ci		}
332062306a36Sopenharmony_ci		pid = event->context_switch.next_prev_pid;
332162306a36Sopenharmony_ci		tid = event->context_switch.next_prev_tid;
332262306a36Sopenharmony_ci	} else {
332362306a36Sopenharmony_ci		if (out)
332462306a36Sopenharmony_ci			return 0;
332562306a36Sopenharmony_ci		pid = sample->pid;
332662306a36Sopenharmony_ci		tid = sample->tid;
332762306a36Sopenharmony_ci	}
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci	if (tid == -1)
333062306a36Sopenharmony_ci		intel_pt_log("context_switch event has no tid\n");
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
333362306a36Sopenharmony_ci	if (ret <= 0)
333462306a36Sopenharmony_ci		return ret;
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	return machine__set_current_tid(pt->machine, cpu, pid, tid);
333762306a36Sopenharmony_ci}
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_cistatic int intel_pt_process_itrace_start(struct intel_pt *pt,
334062306a36Sopenharmony_ci					 union perf_event *event,
334162306a36Sopenharmony_ci					 struct perf_sample *sample)
334262306a36Sopenharmony_ci{
334362306a36Sopenharmony_ci	if (!pt->per_cpu_mmaps)
334462306a36Sopenharmony_ci		return 0;
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	intel_pt_log("itrace_start: cpu %d pid %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
334762306a36Sopenharmony_ci		     sample->cpu, event->itrace_start.pid,
334862306a36Sopenharmony_ci		     event->itrace_start.tid, sample->time,
334962306a36Sopenharmony_ci		     perf_time_to_tsc(sample->time, &pt->tc));
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	return machine__set_current_tid(pt->machine, sample->cpu,
335262306a36Sopenharmony_ci					event->itrace_start.pid,
335362306a36Sopenharmony_ci					event->itrace_start.tid);
335462306a36Sopenharmony_ci}
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_cistatic int intel_pt_process_aux_output_hw_id(struct intel_pt *pt,
335762306a36Sopenharmony_ci					     union perf_event *event,
335862306a36Sopenharmony_ci					     struct perf_sample *sample)
335962306a36Sopenharmony_ci{
336062306a36Sopenharmony_ci	u64 hw_id = event->aux_output_hw_id.hw_id;
336162306a36Sopenharmony_ci	struct auxtrace_queue *queue;
336262306a36Sopenharmony_ci	struct intel_pt_queue *ptq;
336362306a36Sopenharmony_ci	struct evsel *evsel;
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_ci	queue = auxtrace_queues__sample_queue(&pt->queues, sample, pt->session);
336662306a36Sopenharmony_ci	evsel = evlist__id2evsel_strict(pt->session->evlist, sample->id);
336762306a36Sopenharmony_ci	if (!queue || !queue->priv || !evsel || hw_id > INTEL_PT_MAX_PEBS) {
336862306a36Sopenharmony_ci		pr_err("Bad AUX output hardware ID\n");
336962306a36Sopenharmony_ci		return -EINVAL;
337062306a36Sopenharmony_ci	}
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	ptq = queue->priv;
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	ptq->pebs[hw_id].evsel = evsel;
337562306a36Sopenharmony_ci	ptq->pebs[hw_id].id = sample->id;
337662306a36Sopenharmony_ci
337762306a36Sopenharmony_ci	return 0;
337862306a36Sopenharmony_ci}
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_cistatic int intel_pt_find_map(struct thread *thread, u8 cpumode, u64 addr,
338162306a36Sopenharmony_ci			     struct addr_location *al)
338262306a36Sopenharmony_ci{
338362306a36Sopenharmony_ci	if (!al->map || addr < map__start(al->map) || addr >= map__end(al->map)) {
338462306a36Sopenharmony_ci		if (!thread__find_map(thread, cpumode, addr, al))
338562306a36Sopenharmony_ci			return -1;
338662306a36Sopenharmony_ci	}
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	return 0;
338962306a36Sopenharmony_ci}
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci/* Invalidate all instruction cache entries that overlap the text poke */
339262306a36Sopenharmony_cistatic int intel_pt_text_poke(struct intel_pt *pt, union perf_event *event)
339362306a36Sopenharmony_ci{
339462306a36Sopenharmony_ci	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
339562306a36Sopenharmony_ci	u64 addr = event->text_poke.addr + event->text_poke.new_len - 1;
339662306a36Sopenharmony_ci	/* Assume text poke begins in a basic block no more than 4096 bytes */
339762306a36Sopenharmony_ci	int cnt = 4096 + event->text_poke.new_len;
339862306a36Sopenharmony_ci	struct thread *thread = pt->unknown_thread;
339962306a36Sopenharmony_ci	struct addr_location al;
340062306a36Sopenharmony_ci	struct machine *machine = pt->machine;
340162306a36Sopenharmony_ci	struct intel_pt_cache_entry *e;
340262306a36Sopenharmony_ci	u64 offset;
340362306a36Sopenharmony_ci	int ret = 0;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	addr_location__init(&al);
340662306a36Sopenharmony_ci	if (!event->text_poke.new_len)
340762306a36Sopenharmony_ci		goto out;
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	for (; cnt; cnt--, addr--) {
341062306a36Sopenharmony_ci		struct dso *dso;
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci		if (intel_pt_find_map(thread, cpumode, addr, &al)) {
341362306a36Sopenharmony_ci			if (addr < event->text_poke.addr)
341462306a36Sopenharmony_ci				goto out;
341562306a36Sopenharmony_ci			continue;
341662306a36Sopenharmony_ci		}
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci		dso = map__dso(al.map);
341962306a36Sopenharmony_ci		if (!dso || !dso->auxtrace_cache)
342062306a36Sopenharmony_ci			continue;
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci		offset = map__map_ip(al.map, addr);
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci		e = intel_pt_cache_lookup(dso, machine, offset);
342562306a36Sopenharmony_ci		if (!e)
342662306a36Sopenharmony_ci			continue;
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci		if (addr + e->byte_cnt + e->length <= event->text_poke.addr) {
342962306a36Sopenharmony_ci			/*
343062306a36Sopenharmony_ci			 * No overlap. Working backwards there cannot be another
343162306a36Sopenharmony_ci			 * basic block that overlaps the text poke if there is a
343262306a36Sopenharmony_ci			 * branch instruction before the text poke address.
343362306a36Sopenharmony_ci			 */
343462306a36Sopenharmony_ci			if (e->branch != INTEL_PT_BR_NO_BRANCH)
343562306a36Sopenharmony_ci				goto out;
343662306a36Sopenharmony_ci		} else {
343762306a36Sopenharmony_ci			intel_pt_cache_invalidate(dso, machine, offset);
343862306a36Sopenharmony_ci			intel_pt_log("Invalidated instruction cache for %s at %#"PRIx64"\n",
343962306a36Sopenharmony_ci				     dso->long_name, addr);
344062306a36Sopenharmony_ci		}
344162306a36Sopenharmony_ci	}
344262306a36Sopenharmony_ciout:
344362306a36Sopenharmony_ci	addr_location__exit(&al);
344462306a36Sopenharmony_ci	return ret;
344562306a36Sopenharmony_ci}
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_cistatic int intel_pt_process_event(struct perf_session *session,
344862306a36Sopenharmony_ci				  union perf_event *event,
344962306a36Sopenharmony_ci				  struct perf_sample *sample,
345062306a36Sopenharmony_ci				  struct perf_tool *tool)
345162306a36Sopenharmony_ci{
345262306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
345362306a36Sopenharmony_ci					   auxtrace);
345462306a36Sopenharmony_ci	u64 timestamp;
345562306a36Sopenharmony_ci	int err = 0;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	if (dump_trace)
345862306a36Sopenharmony_ci		return 0;
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	if (!tool->ordered_events) {
346162306a36Sopenharmony_ci		pr_err("Intel Processor Trace requires ordered events\n");
346262306a36Sopenharmony_ci		return -EINVAL;
346362306a36Sopenharmony_ci	}
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci	if (sample->time && sample->time != (u64)-1)
346662306a36Sopenharmony_ci		timestamp = perf_time_to_tsc(sample->time, &pt->tc);
346762306a36Sopenharmony_ci	else
346862306a36Sopenharmony_ci		timestamp = 0;
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci	if (timestamp || pt->timeless_decoding) {
347162306a36Sopenharmony_ci		err = intel_pt_update_queues(pt);
347262306a36Sopenharmony_ci		if (err)
347362306a36Sopenharmony_ci			return err;
347462306a36Sopenharmony_ci	}
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	if (pt->timeless_decoding) {
347762306a36Sopenharmony_ci		if (pt->sampling_mode) {
347862306a36Sopenharmony_ci			if (sample->aux_sample.size)
347962306a36Sopenharmony_ci				err = intel_pt_process_timeless_sample(pt,
348062306a36Sopenharmony_ci								       sample);
348162306a36Sopenharmony_ci		} else if (event->header.type == PERF_RECORD_EXIT) {
348262306a36Sopenharmony_ci			err = intel_pt_process_timeless_queues(pt,
348362306a36Sopenharmony_ci							       event->fork.tid,
348462306a36Sopenharmony_ci							       sample->time);
348562306a36Sopenharmony_ci		}
348662306a36Sopenharmony_ci	} else if (timestamp) {
348762306a36Sopenharmony_ci		if (!pt->first_timestamp)
348862306a36Sopenharmony_ci			intel_pt_first_timestamp(pt, timestamp);
348962306a36Sopenharmony_ci		err = intel_pt_process_queues(pt, timestamp);
349062306a36Sopenharmony_ci	}
349162306a36Sopenharmony_ci	if (err)
349262306a36Sopenharmony_ci		return err;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	if (event->header.type == PERF_RECORD_SAMPLE) {
349562306a36Sopenharmony_ci		if (pt->synth_opts.add_callchain && !sample->callchain)
349662306a36Sopenharmony_ci			intel_pt_add_callchain(pt, sample);
349762306a36Sopenharmony_ci		if (pt->synth_opts.add_last_branch && !sample->branch_stack)
349862306a36Sopenharmony_ci			intel_pt_add_br_stack(pt, sample);
349962306a36Sopenharmony_ci	}
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci	if (event->header.type == PERF_RECORD_AUX &&
350262306a36Sopenharmony_ci	    (event->aux.flags & PERF_AUX_FLAG_TRUNCATED) &&
350362306a36Sopenharmony_ci	    pt->synth_opts.errors) {
350462306a36Sopenharmony_ci		err = intel_pt_lost(pt, sample);
350562306a36Sopenharmony_ci		if (err)
350662306a36Sopenharmony_ci			return err;
350762306a36Sopenharmony_ci	}
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
351062306a36Sopenharmony_ci	if (pt->switch_evsel && event->header.type == PERF_RECORD_SAMPLE)
351162306a36Sopenharmony_ci		err = intel_pt_process_switch(pt, sample);
351262306a36Sopenharmony_ci	else
351362306a36Sopenharmony_ci#endif
351462306a36Sopenharmony_ci	if (event->header.type == PERF_RECORD_ITRACE_START)
351562306a36Sopenharmony_ci		err = intel_pt_process_itrace_start(pt, event, sample);
351662306a36Sopenharmony_ci	else if (event->header.type == PERF_RECORD_AUX_OUTPUT_HW_ID)
351762306a36Sopenharmony_ci		err = intel_pt_process_aux_output_hw_id(pt, event, sample);
351862306a36Sopenharmony_ci	else if (event->header.type == PERF_RECORD_SWITCH ||
351962306a36Sopenharmony_ci		 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
352062306a36Sopenharmony_ci		err = intel_pt_context_switch(pt, event, sample);
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci	if (!err && event->header.type == PERF_RECORD_TEXT_POKE)
352362306a36Sopenharmony_ci		err = intel_pt_text_poke(pt, event);
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	if (intel_pt_enable_logging && intel_pt_log_events(pt, sample->time)) {
352662306a36Sopenharmony_ci		intel_pt_log("event %u: cpu %d time %"PRIu64" tsc %#"PRIx64" ",
352762306a36Sopenharmony_ci			     event->header.type, sample->cpu, sample->time, timestamp);
352862306a36Sopenharmony_ci		intel_pt_log_event(event);
352962306a36Sopenharmony_ci	}
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	return err;
353262306a36Sopenharmony_ci}
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_cistatic int intel_pt_flush(struct perf_session *session, struct perf_tool *tool)
353562306a36Sopenharmony_ci{
353662306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
353762306a36Sopenharmony_ci					   auxtrace);
353862306a36Sopenharmony_ci	int ret;
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	if (dump_trace)
354162306a36Sopenharmony_ci		return 0;
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	if (!tool->ordered_events)
354462306a36Sopenharmony_ci		return -EINVAL;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	ret = intel_pt_update_queues(pt);
354762306a36Sopenharmony_ci	if (ret < 0)
354862306a36Sopenharmony_ci		return ret;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	if (pt->timeless_decoding)
355162306a36Sopenharmony_ci		return intel_pt_process_timeless_queues(pt, -1,
355262306a36Sopenharmony_ci							MAX_TIMESTAMP - 1);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	return intel_pt_process_queues(pt, MAX_TIMESTAMP);
355562306a36Sopenharmony_ci}
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_cistatic void intel_pt_free_events(struct perf_session *session)
355862306a36Sopenharmony_ci{
355962306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
356062306a36Sopenharmony_ci					   auxtrace);
356162306a36Sopenharmony_ci	struct auxtrace_queues *queues = &pt->queues;
356262306a36Sopenharmony_ci	unsigned int i;
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
356562306a36Sopenharmony_ci		intel_pt_free_queue(queues->queue_array[i].priv);
356662306a36Sopenharmony_ci		queues->queue_array[i].priv = NULL;
356762306a36Sopenharmony_ci	}
356862306a36Sopenharmony_ci	intel_pt_log_disable();
356962306a36Sopenharmony_ci	auxtrace_queues__free(queues);
357062306a36Sopenharmony_ci}
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_cistatic void intel_pt_free(struct perf_session *session)
357362306a36Sopenharmony_ci{
357462306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
357562306a36Sopenharmony_ci					   auxtrace);
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci	auxtrace_heap__free(&pt->heap);
357862306a36Sopenharmony_ci	intel_pt_free_events(session);
357962306a36Sopenharmony_ci	session->auxtrace = NULL;
358062306a36Sopenharmony_ci	intel_pt_free_vmcs_info(pt);
358162306a36Sopenharmony_ci	thread__put(pt->unknown_thread);
358262306a36Sopenharmony_ci	addr_filters__exit(&pt->filts);
358362306a36Sopenharmony_ci	zfree(&pt->chain);
358462306a36Sopenharmony_ci	zfree(&pt->filter);
358562306a36Sopenharmony_ci	zfree(&pt->time_ranges);
358662306a36Sopenharmony_ci	zfree(&pt->br_stack);
358762306a36Sopenharmony_ci	free(pt);
358862306a36Sopenharmony_ci}
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_cistatic bool intel_pt_evsel_is_auxtrace(struct perf_session *session,
359162306a36Sopenharmony_ci				       struct evsel *evsel)
359262306a36Sopenharmony_ci{
359362306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
359462306a36Sopenharmony_ci					   auxtrace);
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci	return evsel->core.attr.type == pt->pmu_type;
359762306a36Sopenharmony_ci}
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_cistatic int intel_pt_process_auxtrace_event(struct perf_session *session,
360062306a36Sopenharmony_ci					   union perf_event *event,
360162306a36Sopenharmony_ci					   struct perf_tool *tool __maybe_unused)
360262306a36Sopenharmony_ci{
360362306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
360462306a36Sopenharmony_ci					   auxtrace);
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	if (!pt->data_queued) {
360762306a36Sopenharmony_ci		struct auxtrace_buffer *buffer;
360862306a36Sopenharmony_ci		off_t data_offset;
360962306a36Sopenharmony_ci		int fd = perf_data__fd(session->data);
361062306a36Sopenharmony_ci		int err;
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci		if (perf_data__is_pipe(session->data)) {
361362306a36Sopenharmony_ci			data_offset = 0;
361462306a36Sopenharmony_ci		} else {
361562306a36Sopenharmony_ci			data_offset = lseek(fd, 0, SEEK_CUR);
361662306a36Sopenharmony_ci			if (data_offset == -1)
361762306a36Sopenharmony_ci				return -errno;
361862306a36Sopenharmony_ci		}
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci		err = auxtrace_queues__add_event(&pt->queues, session, event,
362162306a36Sopenharmony_ci						 data_offset, &buffer);
362262306a36Sopenharmony_ci		if (err)
362362306a36Sopenharmony_ci			return err;
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci		/* Dump here now we have copied a piped trace out of the pipe */
362662306a36Sopenharmony_ci		if (dump_trace) {
362762306a36Sopenharmony_ci			if (auxtrace_buffer__get_data(buffer, fd)) {
362862306a36Sopenharmony_ci				intel_pt_dump_event(pt, buffer->data,
362962306a36Sopenharmony_ci						    buffer->size);
363062306a36Sopenharmony_ci				auxtrace_buffer__put_data(buffer);
363162306a36Sopenharmony_ci			}
363262306a36Sopenharmony_ci		}
363362306a36Sopenharmony_ci	}
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci	return 0;
363662306a36Sopenharmony_ci}
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_cistatic int intel_pt_queue_data(struct perf_session *session,
363962306a36Sopenharmony_ci			       struct perf_sample *sample,
364062306a36Sopenharmony_ci			       union perf_event *event, u64 data_offset)
364162306a36Sopenharmony_ci{
364262306a36Sopenharmony_ci	struct intel_pt *pt = container_of(session->auxtrace, struct intel_pt,
364362306a36Sopenharmony_ci					   auxtrace);
364462306a36Sopenharmony_ci	u64 timestamp;
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	if (event) {
364762306a36Sopenharmony_ci		return auxtrace_queues__add_event(&pt->queues, session, event,
364862306a36Sopenharmony_ci						  data_offset, NULL);
364962306a36Sopenharmony_ci	}
365062306a36Sopenharmony_ci
365162306a36Sopenharmony_ci	if (sample->time && sample->time != (u64)-1)
365262306a36Sopenharmony_ci		timestamp = perf_time_to_tsc(sample->time, &pt->tc);
365362306a36Sopenharmony_ci	else
365462306a36Sopenharmony_ci		timestamp = 0;
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	return auxtrace_queues__add_sample(&pt->queues, session, sample,
365762306a36Sopenharmony_ci					   data_offset, timestamp);
365862306a36Sopenharmony_ci}
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_cistruct intel_pt_synth {
366162306a36Sopenharmony_ci	struct perf_tool dummy_tool;
366262306a36Sopenharmony_ci	struct perf_session *session;
366362306a36Sopenharmony_ci};
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_cistatic int intel_pt_event_synth(struct perf_tool *tool,
366662306a36Sopenharmony_ci				union perf_event *event,
366762306a36Sopenharmony_ci				struct perf_sample *sample __maybe_unused,
366862306a36Sopenharmony_ci				struct machine *machine __maybe_unused)
366962306a36Sopenharmony_ci{
367062306a36Sopenharmony_ci	struct intel_pt_synth *intel_pt_synth =
367162306a36Sopenharmony_ci			container_of(tool, struct intel_pt_synth, dummy_tool);
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci	return perf_session__deliver_synth_event(intel_pt_synth->session, event,
367462306a36Sopenharmony_ci						 NULL);
367562306a36Sopenharmony_ci}
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_cistatic int intel_pt_synth_event(struct perf_session *session, const char *name,
367862306a36Sopenharmony_ci				struct perf_event_attr *attr, u64 id)
367962306a36Sopenharmony_ci{
368062306a36Sopenharmony_ci	struct intel_pt_synth intel_pt_synth;
368162306a36Sopenharmony_ci	int err;
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_ci	pr_debug("Synthesizing '%s' event with id %" PRIu64 " sample type %#" PRIx64 "\n",
368462306a36Sopenharmony_ci		 name, id, (u64)attr->sample_type);
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci	memset(&intel_pt_synth, 0, sizeof(struct intel_pt_synth));
368762306a36Sopenharmony_ci	intel_pt_synth.session = session;
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci	err = perf_event__synthesize_attr(&intel_pt_synth.dummy_tool, attr, 1,
369062306a36Sopenharmony_ci					  &id, intel_pt_event_synth);
369162306a36Sopenharmony_ci	if (err)
369262306a36Sopenharmony_ci		pr_err("%s: failed to synthesize '%s' event type\n",
369362306a36Sopenharmony_ci		       __func__, name);
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci	return err;
369662306a36Sopenharmony_ci}
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_cistatic void intel_pt_set_event_name(struct evlist *evlist, u64 id,
369962306a36Sopenharmony_ci				    const char *name)
370062306a36Sopenharmony_ci{
370162306a36Sopenharmony_ci	struct evsel *evsel;
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
370462306a36Sopenharmony_ci		if (evsel->core.id && evsel->core.id[0] == id) {
370562306a36Sopenharmony_ci			if (evsel->name)
370662306a36Sopenharmony_ci				zfree(&evsel->name);
370762306a36Sopenharmony_ci			evsel->name = strdup(name);
370862306a36Sopenharmony_ci			break;
370962306a36Sopenharmony_ci		}
371062306a36Sopenharmony_ci	}
371162306a36Sopenharmony_ci}
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_cistatic struct evsel *intel_pt_evsel(struct intel_pt *pt,
371462306a36Sopenharmony_ci					 struct evlist *evlist)
371562306a36Sopenharmony_ci{
371662306a36Sopenharmony_ci	struct evsel *evsel;
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
371962306a36Sopenharmony_ci		if (evsel->core.attr.type == pt->pmu_type && evsel->core.ids)
372062306a36Sopenharmony_ci			return evsel;
372162306a36Sopenharmony_ci	}
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci	return NULL;
372462306a36Sopenharmony_ci}
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_cistatic int intel_pt_synth_events(struct intel_pt *pt,
372762306a36Sopenharmony_ci				 struct perf_session *session)
372862306a36Sopenharmony_ci{
372962306a36Sopenharmony_ci	struct evlist *evlist = session->evlist;
373062306a36Sopenharmony_ci	struct evsel *evsel = intel_pt_evsel(pt, evlist);
373162306a36Sopenharmony_ci	struct perf_event_attr attr;
373262306a36Sopenharmony_ci	u64 id;
373362306a36Sopenharmony_ci	int err;
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	if (!evsel) {
373662306a36Sopenharmony_ci		pr_debug("There are no selected events with Intel Processor Trace data\n");
373762306a36Sopenharmony_ci		return 0;
373862306a36Sopenharmony_ci	}
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	memset(&attr, 0, sizeof(struct perf_event_attr));
374162306a36Sopenharmony_ci	attr.size = sizeof(struct perf_event_attr);
374262306a36Sopenharmony_ci	attr.type = PERF_TYPE_HARDWARE;
374362306a36Sopenharmony_ci	attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK;
374462306a36Sopenharmony_ci	attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID |
374562306a36Sopenharmony_ci			    PERF_SAMPLE_PERIOD;
374662306a36Sopenharmony_ci	if (pt->timeless_decoding)
374762306a36Sopenharmony_ci		attr.sample_type &= ~(u64)PERF_SAMPLE_TIME;
374862306a36Sopenharmony_ci	else
374962306a36Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_TIME;
375062306a36Sopenharmony_ci	if (!pt->per_cpu_mmaps)
375162306a36Sopenharmony_ci		attr.sample_type &= ~(u64)PERF_SAMPLE_CPU;
375262306a36Sopenharmony_ci	attr.exclude_user = evsel->core.attr.exclude_user;
375362306a36Sopenharmony_ci	attr.exclude_kernel = evsel->core.attr.exclude_kernel;
375462306a36Sopenharmony_ci	attr.exclude_hv = evsel->core.attr.exclude_hv;
375562306a36Sopenharmony_ci	attr.exclude_host = evsel->core.attr.exclude_host;
375662306a36Sopenharmony_ci	attr.exclude_guest = evsel->core.attr.exclude_guest;
375762306a36Sopenharmony_ci	attr.sample_id_all = evsel->core.attr.sample_id_all;
375862306a36Sopenharmony_ci	attr.read_format = evsel->core.attr.read_format;
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci	id = evsel->core.id[0] + 1000000000;
376162306a36Sopenharmony_ci	if (!id)
376262306a36Sopenharmony_ci		id = 1;
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci	if (pt->synth_opts.branches) {
376562306a36Sopenharmony_ci		attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
376662306a36Sopenharmony_ci		attr.sample_period = 1;
376762306a36Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_ADDR;
376862306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "branches", &attr, id);
376962306a36Sopenharmony_ci		if (err)
377062306a36Sopenharmony_ci			return err;
377162306a36Sopenharmony_ci		pt->sample_branches = true;
377262306a36Sopenharmony_ci		pt->branches_sample_type = attr.sample_type;
377362306a36Sopenharmony_ci		pt->branches_id = id;
377462306a36Sopenharmony_ci		id += 1;
377562306a36Sopenharmony_ci		attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR;
377662306a36Sopenharmony_ci	}
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci	if (pt->synth_opts.callchain)
377962306a36Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
378062306a36Sopenharmony_ci	if (pt->synth_opts.last_branch) {
378162306a36Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
378262306a36Sopenharmony_ci		/*
378362306a36Sopenharmony_ci		 * We don't use the hardware index, but the sample generation
378462306a36Sopenharmony_ci		 * code uses the new format branch_stack with this field,
378562306a36Sopenharmony_ci		 * so the event attributes must indicate that it's present.
378662306a36Sopenharmony_ci		 */
378762306a36Sopenharmony_ci		attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
378862306a36Sopenharmony_ci	}
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci	if (pt->synth_opts.instructions) {
379162306a36Sopenharmony_ci		attr.config = PERF_COUNT_HW_INSTRUCTIONS;
379262306a36Sopenharmony_ci		if (pt->synth_opts.period_type == PERF_ITRACE_PERIOD_NANOSECS)
379362306a36Sopenharmony_ci			attr.sample_period =
379462306a36Sopenharmony_ci				intel_pt_ns_to_ticks(pt, pt->synth_opts.period);
379562306a36Sopenharmony_ci		else
379662306a36Sopenharmony_ci			attr.sample_period = pt->synth_opts.period;
379762306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "instructions", &attr, id);
379862306a36Sopenharmony_ci		if (err)
379962306a36Sopenharmony_ci			return err;
380062306a36Sopenharmony_ci		pt->sample_instructions = true;
380162306a36Sopenharmony_ci		pt->instructions_sample_type = attr.sample_type;
380262306a36Sopenharmony_ci		pt->instructions_id = id;
380362306a36Sopenharmony_ci		id += 1;
380462306a36Sopenharmony_ci	}
380562306a36Sopenharmony_ci
380662306a36Sopenharmony_ci	if (pt->synth_opts.cycles) {
380762306a36Sopenharmony_ci		attr.config = PERF_COUNT_HW_CPU_CYCLES;
380862306a36Sopenharmony_ci		if (pt->synth_opts.period_type == PERF_ITRACE_PERIOD_NANOSECS)
380962306a36Sopenharmony_ci			attr.sample_period =
381062306a36Sopenharmony_ci				intel_pt_ns_to_ticks(pt, pt->synth_opts.period);
381162306a36Sopenharmony_ci		else
381262306a36Sopenharmony_ci			attr.sample_period = pt->synth_opts.period;
381362306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "cycles", &attr, id);
381462306a36Sopenharmony_ci		if (err)
381562306a36Sopenharmony_ci			return err;
381662306a36Sopenharmony_ci		pt->sample_cycles = true;
381762306a36Sopenharmony_ci		pt->cycles_sample_type = attr.sample_type;
381862306a36Sopenharmony_ci		pt->cycles_id = id;
381962306a36Sopenharmony_ci		id += 1;
382062306a36Sopenharmony_ci	}
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	attr.sample_type &= ~(u64)PERF_SAMPLE_PERIOD;
382362306a36Sopenharmony_ci	attr.sample_period = 1;
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci	if (pt->synth_opts.transactions) {
382662306a36Sopenharmony_ci		attr.config = PERF_COUNT_HW_INSTRUCTIONS;
382762306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "transactions", &attr, id);
382862306a36Sopenharmony_ci		if (err)
382962306a36Sopenharmony_ci			return err;
383062306a36Sopenharmony_ci		pt->sample_transactions = true;
383162306a36Sopenharmony_ci		pt->transactions_sample_type = attr.sample_type;
383262306a36Sopenharmony_ci		pt->transactions_id = id;
383362306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "transactions");
383462306a36Sopenharmony_ci		id += 1;
383562306a36Sopenharmony_ci	}
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	attr.type = PERF_TYPE_SYNTH;
383862306a36Sopenharmony_ci	attr.sample_type |= PERF_SAMPLE_RAW;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	if (pt->synth_opts.ptwrites) {
384162306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_PTWRITE;
384262306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "ptwrite", &attr, id);
384362306a36Sopenharmony_ci		if (err)
384462306a36Sopenharmony_ci			return err;
384562306a36Sopenharmony_ci		pt->sample_ptwrites = true;
384662306a36Sopenharmony_ci		pt->ptwrites_sample_type = attr.sample_type;
384762306a36Sopenharmony_ci		pt->ptwrites_id = id;
384862306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "ptwrite");
384962306a36Sopenharmony_ci		id += 1;
385062306a36Sopenharmony_ci	}
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ci	if (pt->synth_opts.pwr_events) {
385362306a36Sopenharmony_ci		pt->sample_pwr_events = true;
385462306a36Sopenharmony_ci		pt->pwr_events_sample_type = attr.sample_type;
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_CBR;
385762306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "cbr", &attr, id);
385862306a36Sopenharmony_ci		if (err)
385962306a36Sopenharmony_ci			return err;
386062306a36Sopenharmony_ci		pt->cbr_id = id;
386162306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "cbr");
386262306a36Sopenharmony_ci		id += 1;
386362306a36Sopenharmony_ci
386462306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_PSB;
386562306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "psb", &attr, id);
386662306a36Sopenharmony_ci		if (err)
386762306a36Sopenharmony_ci			return err;
386862306a36Sopenharmony_ci		pt->psb_id = id;
386962306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "psb");
387062306a36Sopenharmony_ci		id += 1;
387162306a36Sopenharmony_ci	}
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_ci	if (pt->synth_opts.pwr_events && (evsel->core.attr.config & INTEL_PT_CFG_PWR_EVT_EN)) {
387462306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_MWAIT;
387562306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "mwait", &attr, id);
387662306a36Sopenharmony_ci		if (err)
387762306a36Sopenharmony_ci			return err;
387862306a36Sopenharmony_ci		pt->mwait_id = id;
387962306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "mwait");
388062306a36Sopenharmony_ci		id += 1;
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_PWRE;
388362306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "pwre", &attr, id);
388462306a36Sopenharmony_ci		if (err)
388562306a36Sopenharmony_ci			return err;
388662306a36Sopenharmony_ci		pt->pwre_id = id;
388762306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "pwre");
388862306a36Sopenharmony_ci		id += 1;
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_EXSTOP;
389162306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "exstop", &attr, id);
389262306a36Sopenharmony_ci		if (err)
389362306a36Sopenharmony_ci			return err;
389462306a36Sopenharmony_ci		pt->exstop_id = id;
389562306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "exstop");
389662306a36Sopenharmony_ci		id += 1;
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_PWRX;
389962306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "pwrx", &attr, id);
390062306a36Sopenharmony_ci		if (err)
390162306a36Sopenharmony_ci			return err;
390262306a36Sopenharmony_ci		pt->pwrx_id = id;
390362306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "pwrx");
390462306a36Sopenharmony_ci		id += 1;
390562306a36Sopenharmony_ci	}
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci	if (pt->synth_opts.intr_events && (evsel->core.attr.config & INTEL_PT_CFG_EVT_EN)) {
390862306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_EVT;
390962306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "evt", &attr, id);
391062306a36Sopenharmony_ci		if (err)
391162306a36Sopenharmony_ci			return err;
391262306a36Sopenharmony_ci		pt->evt_sample_type = attr.sample_type;
391362306a36Sopenharmony_ci		pt->evt_id = id;
391462306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "evt");
391562306a36Sopenharmony_ci		id += 1;
391662306a36Sopenharmony_ci	}
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	if (pt->synth_opts.intr_events && pt->cap_event_trace) {
391962306a36Sopenharmony_ci		attr.config = PERF_SYNTH_INTEL_IFLAG_CHG;
392062306a36Sopenharmony_ci		err = intel_pt_synth_event(session, "iflag", &attr, id);
392162306a36Sopenharmony_ci		if (err)
392262306a36Sopenharmony_ci			return err;
392362306a36Sopenharmony_ci		pt->iflag_chg_sample_type = attr.sample_type;
392462306a36Sopenharmony_ci		pt->iflag_chg_id = id;
392562306a36Sopenharmony_ci		intel_pt_set_event_name(evlist, id, "iflag");
392662306a36Sopenharmony_ci		id += 1;
392762306a36Sopenharmony_ci	}
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci	return 0;
393062306a36Sopenharmony_ci}
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_cistatic void intel_pt_setup_pebs_events(struct intel_pt *pt)
393362306a36Sopenharmony_ci{
393462306a36Sopenharmony_ci	struct evsel *evsel;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	if (!pt->synth_opts.other_events)
393762306a36Sopenharmony_ci		return;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	evlist__for_each_entry(pt->session->evlist, evsel) {
394062306a36Sopenharmony_ci		if (evsel->core.attr.aux_output && evsel->core.id) {
394162306a36Sopenharmony_ci			if (pt->single_pebs) {
394262306a36Sopenharmony_ci				pt->single_pebs = false;
394362306a36Sopenharmony_ci				return;
394462306a36Sopenharmony_ci			}
394562306a36Sopenharmony_ci			pt->single_pebs = true;
394662306a36Sopenharmony_ci			pt->sample_pebs = true;
394762306a36Sopenharmony_ci			pt->pebs_evsel = evsel;
394862306a36Sopenharmony_ci		}
394962306a36Sopenharmony_ci	}
395062306a36Sopenharmony_ci}
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_cistatic struct evsel *intel_pt_find_sched_switch(struct evlist *evlist)
395362306a36Sopenharmony_ci{
395462306a36Sopenharmony_ci	struct evsel *evsel;
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	evlist__for_each_entry_reverse(evlist, evsel) {
395762306a36Sopenharmony_ci		const char *name = evsel__name(evsel);
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci		if (!strcmp(name, "sched:sched_switch"))
396062306a36Sopenharmony_ci			return evsel;
396162306a36Sopenharmony_ci	}
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ci	return NULL;
396462306a36Sopenharmony_ci}
396562306a36Sopenharmony_ci
396662306a36Sopenharmony_cistatic bool intel_pt_find_switch(struct evlist *evlist)
396762306a36Sopenharmony_ci{
396862306a36Sopenharmony_ci	struct evsel *evsel;
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
397162306a36Sopenharmony_ci		if (evsel->core.attr.context_switch)
397262306a36Sopenharmony_ci			return true;
397362306a36Sopenharmony_ci	}
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci	return false;
397662306a36Sopenharmony_ci}
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_cistatic int intel_pt_perf_config(const char *var, const char *value, void *data)
397962306a36Sopenharmony_ci{
398062306a36Sopenharmony_ci	struct intel_pt *pt = data;
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci	if (!strcmp(var, "intel-pt.mispred-all"))
398362306a36Sopenharmony_ci		pt->mispred_all = perf_config_bool(var, value);
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_ci	if (!strcmp(var, "intel-pt.max-loops"))
398662306a36Sopenharmony_ci		perf_config_int(&pt->max_loops, var, value);
398762306a36Sopenharmony_ci
398862306a36Sopenharmony_ci	return 0;
398962306a36Sopenharmony_ci}
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci/* Find least TSC which converts to ns or later */
399262306a36Sopenharmony_cistatic u64 intel_pt_tsc_start(u64 ns, struct intel_pt *pt)
399362306a36Sopenharmony_ci{
399462306a36Sopenharmony_ci	u64 tsc, tm;
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci	tsc = perf_time_to_tsc(ns, &pt->tc);
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_ci	while (1) {
399962306a36Sopenharmony_ci		tm = tsc_to_perf_time(tsc, &pt->tc);
400062306a36Sopenharmony_ci		if (tm < ns)
400162306a36Sopenharmony_ci			break;
400262306a36Sopenharmony_ci		tsc -= 1;
400362306a36Sopenharmony_ci	}
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci	while (tm < ns)
400662306a36Sopenharmony_ci		tm = tsc_to_perf_time(++tsc, &pt->tc);
400762306a36Sopenharmony_ci
400862306a36Sopenharmony_ci	return tsc;
400962306a36Sopenharmony_ci}
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_ci/* Find greatest TSC which converts to ns or earlier */
401262306a36Sopenharmony_cistatic u64 intel_pt_tsc_end(u64 ns, struct intel_pt *pt)
401362306a36Sopenharmony_ci{
401462306a36Sopenharmony_ci	u64 tsc, tm;
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci	tsc = perf_time_to_tsc(ns, &pt->tc);
401762306a36Sopenharmony_ci
401862306a36Sopenharmony_ci	while (1) {
401962306a36Sopenharmony_ci		tm = tsc_to_perf_time(tsc, &pt->tc);
402062306a36Sopenharmony_ci		if (tm > ns)
402162306a36Sopenharmony_ci			break;
402262306a36Sopenharmony_ci		tsc += 1;
402362306a36Sopenharmony_ci	}
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci	while (tm > ns)
402662306a36Sopenharmony_ci		tm = tsc_to_perf_time(--tsc, &pt->tc);
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	return tsc;
402962306a36Sopenharmony_ci}
403062306a36Sopenharmony_ci
403162306a36Sopenharmony_cistatic int intel_pt_setup_time_ranges(struct intel_pt *pt,
403262306a36Sopenharmony_ci				      struct itrace_synth_opts *opts)
403362306a36Sopenharmony_ci{
403462306a36Sopenharmony_ci	struct perf_time_interval *p = opts->ptime_range;
403562306a36Sopenharmony_ci	int n = opts->range_num;
403662306a36Sopenharmony_ci	int i;
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_ci	if (!n || !p || pt->timeless_decoding)
403962306a36Sopenharmony_ci		return 0;
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci	pt->time_ranges = calloc(n, sizeof(struct range));
404262306a36Sopenharmony_ci	if (!pt->time_ranges)
404362306a36Sopenharmony_ci		return -ENOMEM;
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_ci	pt->range_cnt = n;
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_ci	intel_pt_log("%s: %u range(s)\n", __func__, n);
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
405062306a36Sopenharmony_ci		struct range *r = &pt->time_ranges[i];
405162306a36Sopenharmony_ci		u64 ts = p[i].start;
405262306a36Sopenharmony_ci		u64 te = p[i].end;
405362306a36Sopenharmony_ci
405462306a36Sopenharmony_ci		/*
405562306a36Sopenharmony_ci		 * Take care to ensure the TSC range matches the perf-time range
405662306a36Sopenharmony_ci		 * when converted back to perf-time.
405762306a36Sopenharmony_ci		 */
405862306a36Sopenharmony_ci		r->start = ts ? intel_pt_tsc_start(ts, pt) : 0;
405962306a36Sopenharmony_ci		r->end   = te ? intel_pt_tsc_end(te, pt) : 0;
406062306a36Sopenharmony_ci
406162306a36Sopenharmony_ci		intel_pt_log("range %d: perf time interval: %"PRIu64" to %"PRIu64"\n",
406262306a36Sopenharmony_ci			     i, ts, te);
406362306a36Sopenharmony_ci		intel_pt_log("range %d: TSC time interval: %#"PRIx64" to %#"PRIx64"\n",
406462306a36Sopenharmony_ci			     i, r->start, r->end);
406562306a36Sopenharmony_ci	}
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci	return 0;
406862306a36Sopenharmony_ci}
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_cistatic int intel_pt_parse_vm_tm_corr_arg(struct intel_pt *pt, char **args)
407162306a36Sopenharmony_ci{
407262306a36Sopenharmony_ci	struct intel_pt_vmcs_info *vmcs_info;
407362306a36Sopenharmony_ci	u64 tsc_offset, vmcs;
407462306a36Sopenharmony_ci	char *p = *args;
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	errno = 0;
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ci	p = skip_spaces(p);
407962306a36Sopenharmony_ci	if (!*p)
408062306a36Sopenharmony_ci		return 1;
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_ci	tsc_offset = strtoull(p, &p, 0);
408362306a36Sopenharmony_ci	if (errno)
408462306a36Sopenharmony_ci		return -errno;
408562306a36Sopenharmony_ci	p = skip_spaces(p);
408662306a36Sopenharmony_ci	if (*p != ':') {
408762306a36Sopenharmony_ci		pt->dflt_tsc_offset = tsc_offset;
408862306a36Sopenharmony_ci		*args = p;
408962306a36Sopenharmony_ci		return 0;
409062306a36Sopenharmony_ci	}
409162306a36Sopenharmony_ci	p += 1;
409262306a36Sopenharmony_ci	while (1) {
409362306a36Sopenharmony_ci		vmcs = strtoull(p, &p, 0);
409462306a36Sopenharmony_ci		if (errno)
409562306a36Sopenharmony_ci			return -errno;
409662306a36Sopenharmony_ci		if (!vmcs)
409762306a36Sopenharmony_ci			return -EINVAL;
409862306a36Sopenharmony_ci		vmcs_info = intel_pt_findnew_vmcs(&pt->vmcs_info, vmcs, tsc_offset);
409962306a36Sopenharmony_ci		if (!vmcs_info)
410062306a36Sopenharmony_ci			return -ENOMEM;
410162306a36Sopenharmony_ci		p = skip_spaces(p);
410262306a36Sopenharmony_ci		if (*p != ',')
410362306a36Sopenharmony_ci			break;
410462306a36Sopenharmony_ci		p += 1;
410562306a36Sopenharmony_ci	}
410662306a36Sopenharmony_ci	*args = p;
410762306a36Sopenharmony_ci	return 0;
410862306a36Sopenharmony_ci}
410962306a36Sopenharmony_ci
411062306a36Sopenharmony_cistatic int intel_pt_parse_vm_tm_corr_args(struct intel_pt *pt)
411162306a36Sopenharmony_ci{
411262306a36Sopenharmony_ci	char *args = pt->synth_opts.vm_tm_corr_args;
411362306a36Sopenharmony_ci	int ret;
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_ci	if (!args)
411662306a36Sopenharmony_ci		return 0;
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci	do {
411962306a36Sopenharmony_ci		ret = intel_pt_parse_vm_tm_corr_arg(pt, &args);
412062306a36Sopenharmony_ci	} while (!ret);
412162306a36Sopenharmony_ci
412262306a36Sopenharmony_ci	if (ret < 0) {
412362306a36Sopenharmony_ci		pr_err("Failed to parse VM Time Correlation options\n");
412462306a36Sopenharmony_ci		return ret;
412562306a36Sopenharmony_ci	}
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	return 0;
412862306a36Sopenharmony_ci}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_cistatic const char * const intel_pt_info_fmts[] = {
413162306a36Sopenharmony_ci	[INTEL_PT_PMU_TYPE]		= "  PMU Type            %"PRId64"\n",
413262306a36Sopenharmony_ci	[INTEL_PT_TIME_SHIFT]		= "  Time Shift          %"PRIu64"\n",
413362306a36Sopenharmony_ci	[INTEL_PT_TIME_MULT]		= "  Time Muliplier      %"PRIu64"\n",
413462306a36Sopenharmony_ci	[INTEL_PT_TIME_ZERO]		= "  Time Zero           %"PRIu64"\n",
413562306a36Sopenharmony_ci	[INTEL_PT_CAP_USER_TIME_ZERO]	= "  Cap Time Zero       %"PRId64"\n",
413662306a36Sopenharmony_ci	[INTEL_PT_TSC_BIT]		= "  TSC bit             %#"PRIx64"\n",
413762306a36Sopenharmony_ci	[INTEL_PT_NORETCOMP_BIT]	= "  NoRETComp bit       %#"PRIx64"\n",
413862306a36Sopenharmony_ci	[INTEL_PT_HAVE_SCHED_SWITCH]	= "  Have sched_switch   %"PRId64"\n",
413962306a36Sopenharmony_ci	[INTEL_PT_SNAPSHOT_MODE]	= "  Snapshot mode       %"PRId64"\n",
414062306a36Sopenharmony_ci	[INTEL_PT_PER_CPU_MMAPS]	= "  Per-cpu maps        %"PRId64"\n",
414162306a36Sopenharmony_ci	[INTEL_PT_MTC_BIT]		= "  MTC bit             %#"PRIx64"\n",
414262306a36Sopenharmony_ci	[INTEL_PT_MTC_FREQ_BITS]	= "  MTC freq bits       %#"PRIx64"\n",
414362306a36Sopenharmony_ci	[INTEL_PT_TSC_CTC_N]		= "  TSC:CTC numerator   %"PRIu64"\n",
414462306a36Sopenharmony_ci	[INTEL_PT_TSC_CTC_D]		= "  TSC:CTC denominator %"PRIu64"\n",
414562306a36Sopenharmony_ci	[INTEL_PT_CYC_BIT]		= "  CYC bit             %#"PRIx64"\n",
414662306a36Sopenharmony_ci	[INTEL_PT_MAX_NONTURBO_RATIO]	= "  Max non-turbo ratio %"PRIu64"\n",
414762306a36Sopenharmony_ci	[INTEL_PT_FILTER_STR_LEN]	= "  Filter string len.  %"PRIu64"\n",
414862306a36Sopenharmony_ci};
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_cistatic void intel_pt_print_info(__u64 *arr, int start, int finish)
415162306a36Sopenharmony_ci{
415262306a36Sopenharmony_ci	int i;
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci	if (!dump_trace)
415562306a36Sopenharmony_ci		return;
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci	for (i = start; i <= finish; i++) {
415862306a36Sopenharmony_ci		const char *fmt = intel_pt_info_fmts[i];
415962306a36Sopenharmony_ci
416062306a36Sopenharmony_ci		if (fmt)
416162306a36Sopenharmony_ci			fprintf(stdout, fmt, arr[i]);
416262306a36Sopenharmony_ci	}
416362306a36Sopenharmony_ci}
416462306a36Sopenharmony_ci
416562306a36Sopenharmony_cistatic void intel_pt_print_info_str(const char *name, const char *str)
416662306a36Sopenharmony_ci{
416762306a36Sopenharmony_ci	if (!dump_trace)
416862306a36Sopenharmony_ci		return;
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	fprintf(stdout, "  %-20s%s\n", name, str ? str : "");
417162306a36Sopenharmony_ci}
417262306a36Sopenharmony_ci
417362306a36Sopenharmony_cistatic bool intel_pt_has(struct perf_record_auxtrace_info *auxtrace_info, int pos)
417462306a36Sopenharmony_ci{
417562306a36Sopenharmony_ci	return auxtrace_info->header.size >=
417662306a36Sopenharmony_ci		sizeof(struct perf_record_auxtrace_info) + (sizeof(u64) * (pos + 1));
417762306a36Sopenharmony_ci}
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ciint intel_pt_process_auxtrace_info(union perf_event *event,
418062306a36Sopenharmony_ci				   struct perf_session *session)
418162306a36Sopenharmony_ci{
418262306a36Sopenharmony_ci	struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
418362306a36Sopenharmony_ci	size_t min_sz = sizeof(u64) * INTEL_PT_PER_CPU_MMAPS;
418462306a36Sopenharmony_ci	struct intel_pt *pt;
418562306a36Sopenharmony_ci	void *info_end;
418662306a36Sopenharmony_ci	__u64 *info;
418762306a36Sopenharmony_ci	int err;
418862306a36Sopenharmony_ci
418962306a36Sopenharmony_ci	if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
419062306a36Sopenharmony_ci					min_sz)
419162306a36Sopenharmony_ci		return -EINVAL;
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	pt = zalloc(sizeof(struct intel_pt));
419462306a36Sopenharmony_ci	if (!pt)
419562306a36Sopenharmony_ci		return -ENOMEM;
419662306a36Sopenharmony_ci
419762306a36Sopenharmony_ci	pt->vmcs_info = RB_ROOT;
419862306a36Sopenharmony_ci
419962306a36Sopenharmony_ci	addr_filters__init(&pt->filts);
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci	err = perf_config(intel_pt_perf_config, pt);
420262306a36Sopenharmony_ci	if (err)
420362306a36Sopenharmony_ci		goto err_free;
420462306a36Sopenharmony_ci
420562306a36Sopenharmony_ci	err = auxtrace_queues__init(&pt->queues);
420662306a36Sopenharmony_ci	if (err)
420762306a36Sopenharmony_ci		goto err_free;
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	if (session->itrace_synth_opts->set) {
421062306a36Sopenharmony_ci		pt->synth_opts = *session->itrace_synth_opts;
421162306a36Sopenharmony_ci	} else {
421262306a36Sopenharmony_ci		struct itrace_synth_opts *opts = session->itrace_synth_opts;
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_ci		itrace_synth_opts__set_default(&pt->synth_opts, opts->default_no_sample);
421562306a36Sopenharmony_ci		if (!opts->default_no_sample && !opts->inject) {
421662306a36Sopenharmony_ci			pt->synth_opts.branches = false;
421762306a36Sopenharmony_ci			pt->synth_opts.callchain = true;
421862306a36Sopenharmony_ci			pt->synth_opts.add_callchain = true;
421962306a36Sopenharmony_ci		}
422062306a36Sopenharmony_ci		pt->synth_opts.thread_stack = opts->thread_stack;
422162306a36Sopenharmony_ci	}
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_ci	if (!(pt->synth_opts.log_plus_flags & AUXTRACE_LOG_FLG_USE_STDOUT))
422462306a36Sopenharmony_ci		intel_pt_log_set_name(INTEL_PT_PMU_NAME);
422562306a36Sopenharmony_ci
422662306a36Sopenharmony_ci	pt->session = session;
422762306a36Sopenharmony_ci	pt->machine = &session->machines.host; /* No kvm support */
422862306a36Sopenharmony_ci	pt->auxtrace_type = auxtrace_info->type;
422962306a36Sopenharmony_ci	pt->pmu_type = auxtrace_info->priv[INTEL_PT_PMU_TYPE];
423062306a36Sopenharmony_ci	pt->tc.time_shift = auxtrace_info->priv[INTEL_PT_TIME_SHIFT];
423162306a36Sopenharmony_ci	pt->tc.time_mult = auxtrace_info->priv[INTEL_PT_TIME_MULT];
423262306a36Sopenharmony_ci	pt->tc.time_zero = auxtrace_info->priv[INTEL_PT_TIME_ZERO];
423362306a36Sopenharmony_ci	pt->cap_user_time_zero = auxtrace_info->priv[INTEL_PT_CAP_USER_TIME_ZERO];
423462306a36Sopenharmony_ci	pt->tsc_bit = auxtrace_info->priv[INTEL_PT_TSC_BIT];
423562306a36Sopenharmony_ci	pt->noretcomp_bit = auxtrace_info->priv[INTEL_PT_NORETCOMP_BIT];
423662306a36Sopenharmony_ci	pt->have_sched_switch = auxtrace_info->priv[INTEL_PT_HAVE_SCHED_SWITCH];
423762306a36Sopenharmony_ci	pt->snapshot_mode = auxtrace_info->priv[INTEL_PT_SNAPSHOT_MODE];
423862306a36Sopenharmony_ci	pt->per_cpu_mmaps = auxtrace_info->priv[INTEL_PT_PER_CPU_MMAPS];
423962306a36Sopenharmony_ci	intel_pt_print_info(&auxtrace_info->priv[0], INTEL_PT_PMU_TYPE,
424062306a36Sopenharmony_ci			    INTEL_PT_PER_CPU_MMAPS);
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	if (intel_pt_has(auxtrace_info, INTEL_PT_CYC_BIT)) {
424362306a36Sopenharmony_ci		pt->mtc_bit = auxtrace_info->priv[INTEL_PT_MTC_BIT];
424462306a36Sopenharmony_ci		pt->mtc_freq_bits = auxtrace_info->priv[INTEL_PT_MTC_FREQ_BITS];
424562306a36Sopenharmony_ci		pt->tsc_ctc_ratio_n = auxtrace_info->priv[INTEL_PT_TSC_CTC_N];
424662306a36Sopenharmony_ci		pt->tsc_ctc_ratio_d = auxtrace_info->priv[INTEL_PT_TSC_CTC_D];
424762306a36Sopenharmony_ci		pt->cyc_bit = auxtrace_info->priv[INTEL_PT_CYC_BIT];
424862306a36Sopenharmony_ci		intel_pt_print_info(&auxtrace_info->priv[0], INTEL_PT_MTC_BIT,
424962306a36Sopenharmony_ci				    INTEL_PT_CYC_BIT);
425062306a36Sopenharmony_ci	}
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci	if (intel_pt_has(auxtrace_info, INTEL_PT_MAX_NONTURBO_RATIO)) {
425362306a36Sopenharmony_ci		pt->max_non_turbo_ratio =
425462306a36Sopenharmony_ci			auxtrace_info->priv[INTEL_PT_MAX_NONTURBO_RATIO];
425562306a36Sopenharmony_ci		intel_pt_print_info(&auxtrace_info->priv[0],
425662306a36Sopenharmony_ci				    INTEL_PT_MAX_NONTURBO_RATIO,
425762306a36Sopenharmony_ci				    INTEL_PT_MAX_NONTURBO_RATIO);
425862306a36Sopenharmony_ci	}
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ci	info = &auxtrace_info->priv[INTEL_PT_FILTER_STR_LEN] + 1;
426162306a36Sopenharmony_ci	info_end = (void *)auxtrace_info + auxtrace_info->header.size;
426262306a36Sopenharmony_ci
426362306a36Sopenharmony_ci	if (intel_pt_has(auxtrace_info, INTEL_PT_FILTER_STR_LEN)) {
426462306a36Sopenharmony_ci		size_t len;
426562306a36Sopenharmony_ci
426662306a36Sopenharmony_ci		len = auxtrace_info->priv[INTEL_PT_FILTER_STR_LEN];
426762306a36Sopenharmony_ci		intel_pt_print_info(&auxtrace_info->priv[0],
426862306a36Sopenharmony_ci				    INTEL_PT_FILTER_STR_LEN,
426962306a36Sopenharmony_ci				    INTEL_PT_FILTER_STR_LEN);
427062306a36Sopenharmony_ci		if (len) {
427162306a36Sopenharmony_ci			const char *filter = (const char *)info;
427262306a36Sopenharmony_ci
427362306a36Sopenharmony_ci			len = roundup(len + 1, 8);
427462306a36Sopenharmony_ci			info += len >> 3;
427562306a36Sopenharmony_ci			if ((void *)info > info_end) {
427662306a36Sopenharmony_ci				pr_err("%s: bad filter string length\n", __func__);
427762306a36Sopenharmony_ci				err = -EINVAL;
427862306a36Sopenharmony_ci				goto err_free_queues;
427962306a36Sopenharmony_ci			}
428062306a36Sopenharmony_ci			pt->filter = memdup(filter, len);
428162306a36Sopenharmony_ci			if (!pt->filter) {
428262306a36Sopenharmony_ci				err = -ENOMEM;
428362306a36Sopenharmony_ci				goto err_free_queues;
428462306a36Sopenharmony_ci			}
428562306a36Sopenharmony_ci			if (session->header.needs_swap)
428662306a36Sopenharmony_ci				mem_bswap_64(pt->filter, len);
428762306a36Sopenharmony_ci			if (pt->filter[len - 1]) {
428862306a36Sopenharmony_ci				pr_err("%s: filter string not null terminated\n", __func__);
428962306a36Sopenharmony_ci				err = -EINVAL;
429062306a36Sopenharmony_ci				goto err_free_queues;
429162306a36Sopenharmony_ci			}
429262306a36Sopenharmony_ci			err = addr_filters__parse_bare_filter(&pt->filts,
429362306a36Sopenharmony_ci							      filter);
429462306a36Sopenharmony_ci			if (err)
429562306a36Sopenharmony_ci				goto err_free_queues;
429662306a36Sopenharmony_ci		}
429762306a36Sopenharmony_ci		intel_pt_print_info_str("Filter string", pt->filter);
429862306a36Sopenharmony_ci	}
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci	if ((void *)info < info_end) {
430162306a36Sopenharmony_ci		pt->cap_event_trace = *info++;
430262306a36Sopenharmony_ci		if (dump_trace)
430362306a36Sopenharmony_ci			fprintf(stdout, "  Cap Event Trace     %d\n",
430462306a36Sopenharmony_ci				pt->cap_event_trace);
430562306a36Sopenharmony_ci	}
430662306a36Sopenharmony_ci
430762306a36Sopenharmony_ci	pt->timeless_decoding = intel_pt_timeless_decoding(pt);
430862306a36Sopenharmony_ci	if (pt->timeless_decoding && !pt->tc.time_mult)
430962306a36Sopenharmony_ci		pt->tc.time_mult = 1;
431062306a36Sopenharmony_ci	pt->have_tsc = intel_pt_have_tsc(pt);
431162306a36Sopenharmony_ci	pt->sampling_mode = intel_pt_sampling_mode(pt);
431262306a36Sopenharmony_ci	pt->est_tsc = !pt->timeless_decoding;
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci	if (pt->synth_opts.vm_time_correlation) {
431562306a36Sopenharmony_ci		if (pt->timeless_decoding) {
431662306a36Sopenharmony_ci			pr_err("Intel PT has no time information for VM Time Correlation\n");
431762306a36Sopenharmony_ci			err = -EINVAL;
431862306a36Sopenharmony_ci			goto err_free_queues;
431962306a36Sopenharmony_ci		}
432062306a36Sopenharmony_ci		if (session->itrace_synth_opts->ptime_range) {
432162306a36Sopenharmony_ci			pr_err("Time ranges cannot be specified with VM Time Correlation\n");
432262306a36Sopenharmony_ci			err = -EINVAL;
432362306a36Sopenharmony_ci			goto err_free_queues;
432462306a36Sopenharmony_ci		}
432562306a36Sopenharmony_ci		/* Currently TSC Offset is calculated using MTC packets */
432662306a36Sopenharmony_ci		if (!intel_pt_have_mtc(pt)) {
432762306a36Sopenharmony_ci			pr_err("MTC packets must have been enabled for VM Time Correlation\n");
432862306a36Sopenharmony_ci			err = -EINVAL;
432962306a36Sopenharmony_ci			goto err_free_queues;
433062306a36Sopenharmony_ci		}
433162306a36Sopenharmony_ci		err = intel_pt_parse_vm_tm_corr_args(pt);
433262306a36Sopenharmony_ci		if (err)
433362306a36Sopenharmony_ci			goto err_free_queues;
433462306a36Sopenharmony_ci	}
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci	pt->unknown_thread = thread__new(999999999, 999999999);
433762306a36Sopenharmony_ci	if (!pt->unknown_thread) {
433862306a36Sopenharmony_ci		err = -ENOMEM;
433962306a36Sopenharmony_ci		goto err_free_queues;
434062306a36Sopenharmony_ci	}
434162306a36Sopenharmony_ci
434262306a36Sopenharmony_ci	err = thread__set_comm(pt->unknown_thread, "unknown", 0);
434362306a36Sopenharmony_ci	if (err)
434462306a36Sopenharmony_ci		goto err_delete_thread;
434562306a36Sopenharmony_ci	if (thread__init_maps(pt->unknown_thread, pt->machine)) {
434662306a36Sopenharmony_ci		err = -ENOMEM;
434762306a36Sopenharmony_ci		goto err_delete_thread;
434862306a36Sopenharmony_ci	}
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci	pt->auxtrace.process_event = intel_pt_process_event;
435162306a36Sopenharmony_ci	pt->auxtrace.process_auxtrace_event = intel_pt_process_auxtrace_event;
435262306a36Sopenharmony_ci	pt->auxtrace.queue_data = intel_pt_queue_data;
435362306a36Sopenharmony_ci	pt->auxtrace.dump_auxtrace_sample = intel_pt_dump_sample;
435462306a36Sopenharmony_ci	pt->auxtrace.flush_events = intel_pt_flush;
435562306a36Sopenharmony_ci	pt->auxtrace.free_events = intel_pt_free_events;
435662306a36Sopenharmony_ci	pt->auxtrace.free = intel_pt_free;
435762306a36Sopenharmony_ci	pt->auxtrace.evsel_is_auxtrace = intel_pt_evsel_is_auxtrace;
435862306a36Sopenharmony_ci	session->auxtrace = &pt->auxtrace;
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_ci	if (dump_trace)
436162306a36Sopenharmony_ci		return 0;
436262306a36Sopenharmony_ci
436362306a36Sopenharmony_ci	if (pt->have_sched_switch == 1) {
436462306a36Sopenharmony_ci		pt->switch_evsel = intel_pt_find_sched_switch(session->evlist);
436562306a36Sopenharmony_ci		if (!pt->switch_evsel) {
436662306a36Sopenharmony_ci			pr_err("%s: missing sched_switch event\n", __func__);
436762306a36Sopenharmony_ci			err = -EINVAL;
436862306a36Sopenharmony_ci			goto err_delete_thread;
436962306a36Sopenharmony_ci		}
437062306a36Sopenharmony_ci	} else if (pt->have_sched_switch == 2 &&
437162306a36Sopenharmony_ci		   !intel_pt_find_switch(session->evlist)) {
437262306a36Sopenharmony_ci		pr_err("%s: missing context_switch attribute flag\n", __func__);
437362306a36Sopenharmony_ci		err = -EINVAL;
437462306a36Sopenharmony_ci		goto err_delete_thread;
437562306a36Sopenharmony_ci	}
437662306a36Sopenharmony_ci
437762306a36Sopenharmony_ci	if (pt->synth_opts.log) {
437862306a36Sopenharmony_ci		bool log_on_error = pt->synth_opts.log_plus_flags & AUXTRACE_LOG_FLG_ON_ERROR;
437962306a36Sopenharmony_ci		unsigned int log_on_error_size = pt->synth_opts.log_on_error_size;
438062306a36Sopenharmony_ci
438162306a36Sopenharmony_ci		intel_pt_log_enable(log_on_error, log_on_error_size);
438262306a36Sopenharmony_ci	}
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci	/* Maximum non-turbo ratio is TSC freq / 100 MHz */
438562306a36Sopenharmony_ci	if (pt->tc.time_mult) {
438662306a36Sopenharmony_ci		u64 tsc_freq = intel_pt_ns_to_ticks(pt, 1000000000);
438762306a36Sopenharmony_ci
438862306a36Sopenharmony_ci		if (!pt->max_non_turbo_ratio)
438962306a36Sopenharmony_ci			pt->max_non_turbo_ratio =
439062306a36Sopenharmony_ci					(tsc_freq + 50000000) / 100000000;
439162306a36Sopenharmony_ci		intel_pt_log("TSC frequency %"PRIu64"\n", tsc_freq);
439262306a36Sopenharmony_ci		intel_pt_log("Maximum non-turbo ratio %u\n",
439362306a36Sopenharmony_ci			     pt->max_non_turbo_ratio);
439462306a36Sopenharmony_ci		pt->cbr2khz = tsc_freq / pt->max_non_turbo_ratio / 1000;
439562306a36Sopenharmony_ci	}
439662306a36Sopenharmony_ci
439762306a36Sopenharmony_ci	err = intel_pt_setup_time_ranges(pt, session->itrace_synth_opts);
439862306a36Sopenharmony_ci	if (err)
439962306a36Sopenharmony_ci		goto err_delete_thread;
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_ci	if (pt->synth_opts.calls)
440262306a36Sopenharmony_ci		pt->branches_filter |= PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
440362306a36Sopenharmony_ci				       PERF_IP_FLAG_TRACE_END;
440462306a36Sopenharmony_ci	if (pt->synth_opts.returns)
440562306a36Sopenharmony_ci		pt->branches_filter |= PERF_IP_FLAG_RETURN |
440662306a36Sopenharmony_ci				       PERF_IP_FLAG_TRACE_BEGIN;
440762306a36Sopenharmony_ci
440862306a36Sopenharmony_ci	if ((pt->synth_opts.callchain || pt->synth_opts.add_callchain) &&
440962306a36Sopenharmony_ci	    !symbol_conf.use_callchain) {
441062306a36Sopenharmony_ci		symbol_conf.use_callchain = true;
441162306a36Sopenharmony_ci		if (callchain_register_param(&callchain_param) < 0) {
441262306a36Sopenharmony_ci			symbol_conf.use_callchain = false;
441362306a36Sopenharmony_ci			pt->synth_opts.callchain = false;
441462306a36Sopenharmony_ci			pt->synth_opts.add_callchain = false;
441562306a36Sopenharmony_ci		}
441662306a36Sopenharmony_ci	}
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ci	if (pt->synth_opts.add_callchain) {
441962306a36Sopenharmony_ci		err = intel_pt_callchain_init(pt);
442062306a36Sopenharmony_ci		if (err)
442162306a36Sopenharmony_ci			goto err_delete_thread;
442262306a36Sopenharmony_ci	}
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci	if (pt->synth_opts.last_branch || pt->synth_opts.add_last_branch) {
442562306a36Sopenharmony_ci		pt->br_stack_sz = pt->synth_opts.last_branch_sz;
442662306a36Sopenharmony_ci		pt->br_stack_sz_plus = pt->br_stack_sz;
442762306a36Sopenharmony_ci	}
442862306a36Sopenharmony_ci
442962306a36Sopenharmony_ci	if (pt->synth_opts.add_last_branch) {
443062306a36Sopenharmony_ci		err = intel_pt_br_stack_init(pt);
443162306a36Sopenharmony_ci		if (err)
443262306a36Sopenharmony_ci			goto err_delete_thread;
443362306a36Sopenharmony_ci		/*
443462306a36Sopenharmony_ci		 * Additional branch stack size to cater for tracing from the
443562306a36Sopenharmony_ci		 * actual sample ip to where the sample time is recorded.
443662306a36Sopenharmony_ci		 * Measured at about 200 branches, but generously set to 1024.
443762306a36Sopenharmony_ci		 * If kernel space is not being traced, then add just 1 for the
443862306a36Sopenharmony_ci		 * branch to kernel space.
443962306a36Sopenharmony_ci		 */
444062306a36Sopenharmony_ci		if (intel_pt_tracing_kernel(pt))
444162306a36Sopenharmony_ci			pt->br_stack_sz_plus += 1024;
444262306a36Sopenharmony_ci		else
444362306a36Sopenharmony_ci			pt->br_stack_sz_plus += 1;
444462306a36Sopenharmony_ci	}
444562306a36Sopenharmony_ci
444662306a36Sopenharmony_ci	pt->use_thread_stack = pt->synth_opts.callchain ||
444762306a36Sopenharmony_ci			       pt->synth_opts.add_callchain ||
444862306a36Sopenharmony_ci			       pt->synth_opts.thread_stack ||
444962306a36Sopenharmony_ci			       pt->synth_opts.last_branch ||
445062306a36Sopenharmony_ci			       pt->synth_opts.add_last_branch;
445162306a36Sopenharmony_ci
445262306a36Sopenharmony_ci	pt->callstack = pt->synth_opts.callchain ||
445362306a36Sopenharmony_ci			pt->synth_opts.add_callchain ||
445462306a36Sopenharmony_ci			pt->synth_opts.thread_stack;
445562306a36Sopenharmony_ci
445662306a36Sopenharmony_ci	err = intel_pt_synth_events(pt, session);
445762306a36Sopenharmony_ci	if (err)
445862306a36Sopenharmony_ci		goto err_delete_thread;
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_ci	intel_pt_setup_pebs_events(pt);
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_ci	if (perf_data__is_pipe(session->data)) {
446362306a36Sopenharmony_ci		pr_warning("WARNING: Intel PT with pipe mode is not recommended.\n"
446462306a36Sopenharmony_ci			   "         The output cannot relied upon.  In particular,\n"
446562306a36Sopenharmony_ci			   "         timestamps and the order of events may be incorrect.\n");
446662306a36Sopenharmony_ci	}
446762306a36Sopenharmony_ci
446862306a36Sopenharmony_ci	if (pt->sampling_mode || list_empty(&session->auxtrace_index))
446962306a36Sopenharmony_ci		err = auxtrace_queue_data(session, true, true);
447062306a36Sopenharmony_ci	else
447162306a36Sopenharmony_ci		err = auxtrace_queues__process_index(&pt->queues, session);
447262306a36Sopenharmony_ci	if (err)
447362306a36Sopenharmony_ci		goto err_delete_thread;
447462306a36Sopenharmony_ci
447562306a36Sopenharmony_ci	if (pt->queues.populated)
447662306a36Sopenharmony_ci		pt->data_queued = true;
447762306a36Sopenharmony_ci
447862306a36Sopenharmony_ci	if (pt->timeless_decoding)
447962306a36Sopenharmony_ci		pr_debug2("Intel PT decoding without timestamps\n");
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_ci	return 0;
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_cierr_delete_thread:
448462306a36Sopenharmony_ci	zfree(&pt->chain);
448562306a36Sopenharmony_ci	thread__zput(pt->unknown_thread);
448662306a36Sopenharmony_cierr_free_queues:
448762306a36Sopenharmony_ci	intel_pt_log_disable();
448862306a36Sopenharmony_ci	auxtrace_queues__free(&pt->queues);
448962306a36Sopenharmony_ci	session->auxtrace = NULL;
449062306a36Sopenharmony_cierr_free:
449162306a36Sopenharmony_ci	addr_filters__exit(&pt->filts);
449262306a36Sopenharmony_ci	zfree(&pt->filter);
449362306a36Sopenharmony_ci	zfree(&pt->time_ranges);
449462306a36Sopenharmony_ci	free(pt);
449562306a36Sopenharmony_ci	return err;
449662306a36Sopenharmony_ci}
4497