// 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. Load more
// 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",