3261 lines · 79.6 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 INTEL_PT_BLK_SIZE 1024 #define BIT63 (((uint64_t)1 << 63)) #define INTEL_PT_RETURN 1 /* Maximum number of loops with no packets consumed i.e. stuck in a loop */#define INTEL_PT_MAX_LOOPS 10000 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_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_RESAMPLE,}; 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:		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:		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);	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 hop_psb_fup;	bool leap;	enum intel_pt_param_flags flags;	uint64_t pos;	uint64_t last_ip;	uint64_t ip;	uint64_t cr3;	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;	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;	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 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;	int no_progress;	int stuck_ip_prd;	int stuck_ip_cnt;	const unsigned char *next_buf;	size_t next_len;	unsigned char temp_buf[INTEL_PT_PKT_MAX_SZ];}; 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;} 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->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->flags              = params->flags; 	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; 	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;} 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;	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",	[INTEL_PT_ERR_UNK]    = "Unknown error!",	[INTEL_PT_ERR_NELOOP] = "Never-ending loop",}; int intel_pt__strerror(int code, char *buf, size_t buflen){	if (code < 1 || code >= INTEL_PT_ERR_MAX)		code = INTEL_PT_ERR_UNK;	strlcpy(buf, intel_pt_err_msgs[code], buflen);	return 0;} static uint64_t intel_pt_calc_ip(const struct intel_pt_pkt *packet,				 uint64_t last_ip){	uint64_t ip; 	switch (packet->count) {	case 1:		ip = (last_ip & (uint64_t)0xffffffffffff0000ULL) |		     packet->payload;		break;	case 2:		ip = (last_ip & (uint64_t)0xffffffff00000000ULL) |		     packet->payload;		break;	case 3:		ip = packet->payload;		/* Sign-extend 6-byte ip */		if (ip & (uint64_t)0x800000000000ULL)			ip |= (uint64_t)0xffff000000000000ULL;		break;	case 4:		ip = (last_ip & (uint64_t)0xffff000000000000ULL) |		     packet->payload;		break;	case 6:		ip = packet->payload;		break;	default:		return 0;	} 	return ip;} static inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder){	decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip);	decoder->have_last_ip = true;} static inline void intel_pt_set_ip(struct intel_pt_decoder *decoder){	intel_pt_set_last_ip(decoder);	decoder->ip = decoder->last_ip;} static void intel_pt_decoder_log_packet(struct intel_pt_decoder *decoder){	intel_pt_log_packet(&decoder->packet, decoder->pkt_len, decoder->pos,			    decoder->buf);} static int intel_pt_bug(struct intel_pt_decoder *decoder){	intel_pt_log("ERROR: Internal error\n");	decoder->pkt_state = INTEL_PT_STATE_NO_PSB;	return -ENOSYS;} static inline void intel_pt_clear_tx_flags(struct intel_pt_decoder *decoder){	decoder->tx_flags = 0;} static inline void intel_pt_update_in_tx(struct intel_pt_decoder *decoder){	decoder->tx_flags = decoder->packet.payload & INTEL_PT_IN_TX;} static int intel_pt_bad_packet(struct intel_pt_decoder *decoder){	intel_pt_clear_tx_flags(decoder);	decoder->have_tma = false;	decoder->pkt_len = 1;	decoder->pkt_step = 1;	intel_pt_decoder_log_packet(decoder);	if (decoder->pkt_state != INTEL_PT_STATE_NO_PSB) {		intel_pt_log("ERROR: Bad packet\n");		decoder->pkt_state = INTEL_PT_STATE_ERR1;	}	return -EBADMSG;} static inline void intel_pt_update_sample_time(struct intel_pt_decoder *decoder){	decoder->sample_timestamp = decoder->timestamp;

Lines 1–500 of 3261.