// 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. 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 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;