4515 lines · 111.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * intel_pt_decoder.c: Intel Processor Trace support * Copyright (c) 2013-2014, Intel Corporation. */ #ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include <stdlib.h>#include <stdbool.h>#include <string.h>#include <errno.h>#include <stdint.h>#include <inttypes.h>#include <linux/compiler.h>#include <linux/string.h>#include <linux/zalloc.h> #include "../auxtrace.h" #include "intel-pt-insn-decoder.h"#include "intel-pt-pkt-decoder.h"#include "intel-pt-decoder.h"#include "intel-pt-log.h" #define BITULL(x) (1ULL << (x)) /* IA32_RTIT_CTL MSR bits */#define INTEL_PT_CYC_ENABLE		BITULL(1)#define INTEL_PT_CYC_THRESHOLD		(BITULL(22) | BITULL(21) | BITULL(20) | BITULL(19))#define INTEL_PT_CYC_THRESHOLD_SHIFT	19 #define INTEL_PT_BLK_SIZE 1024 #define BIT63 (((uint64_t)1 << 63)) #define SEVEN_BYTES 0xffffffffffffffULL #define NO_VMCS 0xffffffffffULL #define INTEL_PT_RETURN 1 /* * Default maximum number of loops with no packets consumed i.e. stuck in a * loop. */#define INTEL_PT_MAX_LOOPS 100000 struct intel_pt_blk {	struct intel_pt_blk *prev;	uint64_t ip[INTEL_PT_BLK_SIZE];}; struct intel_pt_stack {	struct intel_pt_blk *blk;	struct intel_pt_blk *spare;	int pos;}; enum intel_pt_p_once {	INTEL_PT_PRT_ONCE_UNK_VMCS,	INTEL_PT_PRT_ONCE_ERANGE,}; enum intel_pt_pkt_state {	INTEL_PT_STATE_NO_PSB,	INTEL_PT_STATE_NO_IP,	INTEL_PT_STATE_ERR_RESYNC,	INTEL_PT_STATE_IN_SYNC,	INTEL_PT_STATE_TNT_CONT,	INTEL_PT_STATE_TNT,	INTEL_PT_STATE_TIP,	INTEL_PT_STATE_TIP_PGD,	INTEL_PT_STATE_FUP,	INTEL_PT_STATE_FUP_NO_TIP,	INTEL_PT_STATE_FUP_IN_PSB,	INTEL_PT_STATE_RESAMPLE,	INTEL_PT_STATE_VM_TIME_CORRELATION,}; static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state){	switch (pkt_state) {	case INTEL_PT_STATE_NO_PSB:	case INTEL_PT_STATE_NO_IP:	case INTEL_PT_STATE_ERR_RESYNC:	case INTEL_PT_STATE_IN_SYNC:	case INTEL_PT_STATE_TNT_CONT:	case INTEL_PT_STATE_RESAMPLE:	case INTEL_PT_STATE_VM_TIME_CORRELATION:		return true;	case INTEL_PT_STATE_TNT:	case INTEL_PT_STATE_TIP:	case INTEL_PT_STATE_TIP_PGD:	case INTEL_PT_STATE_FUP:	case INTEL_PT_STATE_FUP_NO_TIP:	case INTEL_PT_STATE_FUP_IN_PSB:		return false;	default:		return true;	};} #ifdef INTEL_PT_STRICT#define INTEL_PT_STATE_ERR1	INTEL_PT_STATE_NO_PSB#define INTEL_PT_STATE_ERR2	INTEL_PT_STATE_NO_PSB#define INTEL_PT_STATE_ERR3	INTEL_PT_STATE_NO_PSB#define INTEL_PT_STATE_ERR4	INTEL_PT_STATE_NO_PSB#else#define INTEL_PT_STATE_ERR1	(decoder->pkt_state)#define INTEL_PT_STATE_ERR2	INTEL_PT_STATE_NO_IP#define INTEL_PT_STATE_ERR3	INTEL_PT_STATE_ERR_RESYNC#define INTEL_PT_STATE_ERR4	INTEL_PT_STATE_IN_SYNC#endif struct intel_pt_decoder {	int (*get_trace)(struct intel_pt_buffer *buffer, void *data);	int (*walk_insn)(struct intel_pt_insn *intel_pt_insn,			 uint64_t *insn_cnt_ptr, uint64_t *ip, uint64_t to_ip,			 uint64_t max_insn_cnt, void *data);	bool (*pgd_ip)(uint64_t ip, void *data);	int (*lookahead)(void *data, intel_pt_lookahead_cb_t cb, void *cb_data);	struct intel_pt_vmcs_info *(*findnew_vmcs_info)(void *data, uint64_t vmcs);	void *data;	struct intel_pt_state state;	const unsigned char *buf;	size_t len;	bool return_compression;	bool branch_enable;	bool mtc_insn;	bool pge;	bool have_tma;	bool have_cyc;	bool fixup_last_mtc;	bool have_last_ip;	bool in_psb;	bool hop;	bool leap;	bool emulated_ptwrite;	bool vm_time_correlation;	bool vm_tm_corr_dry_run;	bool vm_tm_corr_reliable;	bool vm_tm_corr_same_buf;	bool vm_tm_corr_continuous;	bool nr;	bool next_nr;	bool iflag;	bool next_iflag;	enum intel_pt_param_flags flags;	uint64_t pos;	uint64_t last_ip;	uint64_t ip;	uint64_t pip_payload;	uint64_t timestamp;	uint64_t tsc_timestamp;	uint64_t ref_timestamp;	uint64_t buf_timestamp;	uint64_t sample_timestamp;	uint64_t ret_addr;	uint64_t ctc_timestamp;	uint64_t ctc_delta;	uint64_t cycle_cnt;	uint64_t cyc_ref_timestamp;	uint64_t first_timestamp;	uint64_t last_reliable_timestamp;	uint64_t vmcs;	uint64_t print_once;	uint64_t last_ctc;	uint32_t last_mtc;	uint32_t tsc_ctc_ratio_n;	uint32_t tsc_ctc_ratio_d;	uint32_t tsc_ctc_mult;	uint32_t tsc_slip;	uint32_t ctc_rem_mask;	int mtc_shift;	struct intel_pt_stack stack;	enum intel_pt_pkt_state pkt_state;	enum intel_pt_pkt_ctx pkt_ctx;	enum intel_pt_pkt_ctx prev_pkt_ctx;	enum intel_pt_blk_type blk_type;	int blk_type_pos;	struct intel_pt_pkt packet;	struct intel_pt_pkt tnt;	int pkt_step;	int pkt_len;	int last_packet_type;	unsigned int cbr;	unsigned int cbr_seen;	unsigned int max_non_turbo_ratio;	double max_non_turbo_ratio_fp;	double cbr_cyc_to_tsc;	double calc_cyc_to_tsc;	bool have_calc_cyc_to_tsc;	int exec_mode;	unsigned int insn_bytes;	uint64_t period;	enum intel_pt_period_type period_type;	uint64_t tot_insn_cnt;	uint64_t period_insn_cnt;	uint64_t period_mask;	uint64_t period_ticks;	uint64_t last_masked_timestamp;	uint64_t tot_cyc_cnt;	uint64_t sample_tot_cyc_cnt;	uint64_t base_cyc_cnt;	uint64_t cyc_cnt_timestamp;	uint64_t ctl;	uint64_t cyc_threshold;	double tsc_to_cyc;	bool continuous_period;	bool overflow;	bool set_fup_tx_flags;	bool set_fup_ptw;	bool set_fup_mwait;	bool set_fup_pwre;	bool set_fup_exstop;	bool set_fup_bep;	bool set_fup_cfe_ip;	bool set_fup_cfe;	bool set_fup_mode_exec;	bool sample_cyc;	unsigned int fup_tx_flags;	unsigned int tx_flags;	uint64_t fup_ptw_payload;	uint64_t fup_mwait_payload;	uint64_t fup_pwre_payload;	uint64_t cbr_payload;	uint64_t timestamp_insn_cnt;	uint64_t sample_insn_cnt;	uint64_t stuck_ip;	struct intel_pt_pkt fup_cfe_pkt;	int max_loops;	int no_progress;	int stuck_ip_prd;	int stuck_ip_cnt;	uint64_t psb_ip;	const unsigned char *next_buf;	size_t next_len;	unsigned char temp_buf[INTEL_PT_PKT_MAX_SZ];	int evd_cnt;	struct intel_pt_evd evd[INTEL_PT_MAX_EVDS];}; static uint64_t intel_pt_lower_power_of_2(uint64_t x){	int i; 	for (i = 0; x != 1; i++)		x >>= 1; 	return x << i;} __printf(1, 2)static void p_log(const char *fmt, ...){	char buf[512];	va_list args; 	va_start(args, fmt);	vsnprintf(buf, sizeof(buf), fmt, args);	va_end(args); 	fprintf(stderr, "%s\n", buf);	intel_pt_log("%s\n", buf);} static bool intel_pt_print_once(struct intel_pt_decoder *decoder,				enum intel_pt_p_once id){	uint64_t bit = 1ULL << id; 	if (decoder->print_once & bit)		return false;	decoder->print_once |= bit;	return true;} static uint64_t intel_pt_cyc_threshold(uint64_t ctl){	if (!(ctl & INTEL_PT_CYC_ENABLE))		return 0; 	return (ctl & INTEL_PT_CYC_THRESHOLD) >> INTEL_PT_CYC_THRESHOLD_SHIFT;} static void intel_pt_setup_period(struct intel_pt_decoder *decoder){	if (decoder->period_type == INTEL_PT_PERIOD_TICKS) {		uint64_t period; 		period = intel_pt_lower_power_of_2(decoder->period);		decoder->period_mask  = ~(period - 1);		decoder->period_ticks = period;	}} static uint64_t multdiv(uint64_t t, uint32_t n, uint32_t d){	if (!d)		return 0;	return (t / d) * n + ((t % d) * n) / d;} struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params){	struct intel_pt_decoder *decoder; 	if (!params->get_trace || !params->walk_insn)		return NULL; 	decoder = zalloc(sizeof(struct intel_pt_decoder));	if (!decoder)		return NULL; 	decoder->get_trace          = params->get_trace;	decoder->walk_insn          = params->walk_insn;	decoder->pgd_ip             = params->pgd_ip;	decoder->lookahead          = params->lookahead;	decoder->findnew_vmcs_info  = params->findnew_vmcs_info;	decoder->data               = params->data;	decoder->return_compression = params->return_compression;	decoder->branch_enable      = params->branch_enable;	decoder->hop                = params->quick >= 1;	decoder->leap               = params->quick >= 2;	decoder->vm_time_correlation = params->vm_time_correlation;	decoder->vm_tm_corr_dry_run = params->vm_tm_corr_dry_run;	decoder->first_timestamp    = params->first_timestamp;	decoder->last_reliable_timestamp = params->first_timestamp;	decoder->max_loops          = params->max_loops ? params->max_loops : INTEL_PT_MAX_LOOPS; 	decoder->flags              = params->flags; 	decoder->ctl                = params->ctl;	decoder->period             = params->period;	decoder->period_type        = params->period_type; 	decoder->max_non_turbo_ratio    = params->max_non_turbo_ratio;	decoder->max_non_turbo_ratio_fp = params->max_non_turbo_ratio; 	decoder->cyc_threshold = intel_pt_cyc_threshold(decoder->ctl); 	intel_pt_setup_period(decoder); 	decoder->mtc_shift = params->mtc_period;	decoder->ctc_rem_mask = (1 << decoder->mtc_shift) - 1; 	decoder->tsc_ctc_ratio_n = params->tsc_ctc_ratio_n;	decoder->tsc_ctc_ratio_d = params->tsc_ctc_ratio_d; 	if (!decoder->tsc_ctc_ratio_n)		decoder->tsc_ctc_ratio_d = 0; 	if (decoder->tsc_ctc_ratio_d) {		if (!(decoder->tsc_ctc_ratio_n % decoder->tsc_ctc_ratio_d))			decoder->tsc_ctc_mult = decoder->tsc_ctc_ratio_n /						decoder->tsc_ctc_ratio_d;	} 	/*	 * A TSC packet can slip past MTC packets so that the timestamp appears	 * to go backwards. One estimate is that can be up to about 40 CPU	 * cycles, which is certainly less than 0x1000 TSC ticks, but accept	 * slippage an order of magnitude more to be on the safe side.	 */	decoder->tsc_slip = 0x10000; 	intel_pt_log("timestamp: mtc_shift %u\n", decoder->mtc_shift);	intel_pt_log("timestamp: tsc_ctc_ratio_n %u\n", decoder->tsc_ctc_ratio_n);	intel_pt_log("timestamp: tsc_ctc_ratio_d %u\n", decoder->tsc_ctc_ratio_d);	intel_pt_log("timestamp: tsc_ctc_mult %u\n", decoder->tsc_ctc_mult);	intel_pt_log("timestamp: tsc_slip %#x\n", decoder->tsc_slip); 	if (decoder->hop)		intel_pt_log("Hop mode: decoding FUP and TIPs, but not TNT\n"); 	return decoder;} void intel_pt_set_first_timestamp(struct intel_pt_decoder *decoder,				  uint64_t first_timestamp){	decoder->first_timestamp = first_timestamp;} static void intel_pt_pop_blk(struct intel_pt_stack *stack){	struct intel_pt_blk *blk = stack->blk; 	stack->blk = blk->prev;	if (!stack->spare)		stack->spare = blk;	else		free(blk);} static uint64_t intel_pt_pop(struct intel_pt_stack *stack){	if (!stack->pos) {		if (!stack->blk)			return 0;		intel_pt_pop_blk(stack);		if (!stack->blk)			return 0;		stack->pos = INTEL_PT_BLK_SIZE;	}	return stack->blk->ip[--stack->pos];} static int intel_pt_alloc_blk(struct intel_pt_stack *stack){	struct intel_pt_blk *blk; 	if (stack->spare) {		blk = stack->spare;		stack->spare = NULL;	} else {		blk = malloc(sizeof(struct intel_pt_blk));		if (!blk)			return -ENOMEM;	} 	blk->prev = stack->blk;	stack->blk = blk;	stack->pos = 0;	return 0;} static int intel_pt_push(struct intel_pt_stack *stack, uint64_t ip){	int err; 	if (!stack->blk || stack->pos == INTEL_PT_BLK_SIZE) {		err = intel_pt_alloc_blk(stack);		if (err)			return err;	} 	stack->blk->ip[stack->pos++] = ip;	return 0;} static void intel_pt_clear_stack(struct intel_pt_stack *stack){	while (stack->blk)		intel_pt_pop_blk(stack);	stack->pos = 0;} static void intel_pt_free_stack(struct intel_pt_stack *stack){	intel_pt_clear_stack(stack);	zfree(&stack->blk);	zfree(&stack->spare);} void intel_pt_decoder_free(struct intel_pt_decoder *decoder){	intel_pt_free_stack(&decoder->stack);	free(decoder);} static int intel_pt_ext_err(int code){	switch (code) {	case -ENOMEM:		return INTEL_PT_ERR_NOMEM;	case -ENOSYS:		return INTEL_PT_ERR_INTERN;	case -EBADMSG:		return INTEL_PT_ERR_BADPKT;	case -ENODATA:		return INTEL_PT_ERR_NODATA;	case -EILSEQ:		return INTEL_PT_ERR_NOINSN;	case -ENOENT:		return INTEL_PT_ERR_MISMAT;	case -EOVERFLOW:		return INTEL_PT_ERR_OVR;	case -ENOSPC:		return INTEL_PT_ERR_LOST;	case -ELOOP:		return INTEL_PT_ERR_NELOOP;	case -ECONNRESET:		return INTEL_PT_ERR_EPTW;	default:		return INTEL_PT_ERR_UNK;	}} static const char *intel_pt_err_msgs[] = {	[INTEL_PT_ERR_NOMEM]  = "Memory allocation failed",	[INTEL_PT_ERR_INTERN] = "Internal error",	[INTEL_PT_ERR_BADPKT] = "Bad packet",	[INTEL_PT_ERR_NODATA] = "No more data",	[INTEL_PT_ERR_NOINSN] = "Failed to get instruction",	[INTEL_PT_ERR_MISMAT] = "Trace doesn't match instruction",	[INTEL_PT_ERR_OVR]    = "Overflow packet",	[INTEL_PT_ERR_LOST]   = "Lost trace data",

Lines 1–500 of 4515.