staticinlinebool 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: returntrue; 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: returnfalse; default: returntrue;
};
}
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;
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;
}
/* * MTC provides a 8-bit slice of CTC but the TMA packet only provides the lower * 16 bits of CTC. If mtc_shift > 8 then some of the MTC bits are not in the CTC * provided by the TMA packet. Fix-up the last_mtc calculated from the TMA * packet by copying the missing bits from the current MTC assuming the least * difference between the two, and that the current MTC comes after last_mtc.
*/ staticvoid intel_pt_fixup_last_mtc(uint32_t mtc, int mtc_shift,
uint32_t *last_mtc)
{
uint32_t first_missing_bit = 1U << (16 - mtc_shift);
uint32_t mask = ~(first_missing_bit - 1);
switch (pkt_info->packet.type) { case INTEL_PT_TNT: case INTEL_PT_TIP_PGE: case INTEL_PT_TIP: case INTEL_PT_FUP: case INTEL_PT_PSB: case INTEL_PT_PIP: case INTEL_PT_MODE_EXEC: case INTEL_PT_MODE_TSX: case INTEL_PT_PSBEND: case INTEL_PT_PAD: case INTEL_PT_VMCS: case INTEL_PT_MNT: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD: return 0;
case INTEL_PT_TIP_PGD: case INTEL_PT_TRACESTOP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_OVF: case INTEL_PT_BAD: /* Does not happen */ default: return 1;
}
/* * For now, do not support using TSC packets for at least the reasons: * 1) timing might have stopped * 2) TSC packets within PSB+ can slip against CYC packets
*/ if (!from_mtc) return;
switch (decoder->period_type) { case INTEL_PT_PERIOD_INSTRUCTIONS:
decoder->period_insn_cnt = 0; break; case INTEL_PT_PERIOD_TICKS:
timestamp = decoder->timestamp + decoder->timestamp_insn_cnt;
masked_timestamp = timestamp & decoder->period_mask; if (masked_timestamp > decoder->last_masked_timestamp)
decoder->last_masked_timestamp = masked_timestamp; else
decoder->last_masked_timestamp += decoder->period_ticks; break; case INTEL_PT_PERIOD_NONE: case INTEL_PT_PERIOD_MTC: default: break;
}
decoder->state.type |= INTEL_PT_INSTRUCTION;
}
/* * Sample FUP instruction at the same time as reporting the FUP event, so the * instruction sample gets the same flags as the FUP event.
*/ staticvoid intel_pt_sample_fup_insn(struct intel_pt_decoder *decoder)
{ struct intel_pt_insn intel_pt_insn;
uint64_t max_insn_cnt, insn_cnt = 0; int err;
max_insn_cnt = intel_pt_next_sample(decoder); if (max_insn_cnt != 1) return;
err = decoder->walk_insn(&intel_pt_insn, &insn_cnt, &decoder->ip,
0, max_insn_cnt, decoder->data); /* Ignore error, it will be reported next walk anyway */ if (err) return;
if (intel_pt_insn.branch != INTEL_PT_BR_NO_BRANCH) {
intel_pt_log_at("ERROR: Unexpected branch at FUP instruction", decoder->ip); return;
}
/* * Check for being stuck in a loop. This can happen if a * decoder error results in the decoder erroneously setting the * ip to an address that is itself in an infinite loop that * consumes no packets. When that happens, there must be an * unconditional branch.
*/ if (cnt) { if (cnt == 1) {
decoder->stuck_ip = decoder->state.to_ip;
decoder->stuck_ip_prd = 1;
decoder->stuck_ip_cnt = 1;
} elseif (cnt > decoder->max_loops ||
decoder->state.to_ip == decoder->stuck_ip) {
intel_pt_log_at("ERROR: Never-ending loop",
decoder->state.to_ip);
decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;
err = -ELOOP; goto out;
} elseif (!--decoder->stuck_ip_cnt) {
decoder->stuck_ip_prd += 1;
decoder->stuck_ip_cnt = decoder->stuck_ip_prd;
decoder->stuck_ip = decoder->state.to_ip;
}
} goto out_no_progress;
}
out:
decoder->no_progress = 0;
out_no_progress:
decoder->state.insn_op = intel_pt_insn->op;
decoder->state.insn_len = intel_pt_insn->length;
memcpy(decoder->state.insn, intel_pt_insn->buf,
INTEL_PT_INSN_BUF_SZ);
if (decoder->tx_flags & INTEL_PT_IN_TX)
decoder->state.flags |= INTEL_PT_IN_TX;
switch (pkt_info->packet.type) { case INTEL_PT_PAD: case INTEL_PT_MNT: case INTEL_PT_MODE_EXEC: case INTEL_PT_MODE_TSX: case INTEL_PT_MTC: case INTEL_PT_FUP: case INTEL_PT_CYC: case INTEL_PT_CBR: case INTEL_PT_TSC: case INTEL_PT_TMA: case INTEL_PT_PIP: case INTEL_PT_VMCS: case INTEL_PT_PSB: case INTEL_PT_PSBEND: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD: break;
case INTEL_PT_TIP_PGE: case INTEL_PT_TIP_PGD: case INTEL_PT_TIP: case INTEL_PT_BAD: case INTEL_PT_OVF: case INTEL_PT_TRACESTOP: default: return 1;
}
return 0;
}
staticint intel_pt_emulated_ptwrite(struct intel_pt_decoder *decoder)
{ int n = 64 - decoder->tnt.count; struct eptw_data data = {
.bit_countdown = n,
.payload = decoder->tnt.payload >> n,
};
/* For use only when decoder->vm_time_correlation is true */ staticbool intel_pt_time_in_range(struct intel_pt_decoder *decoder,
uint64_t timestamp)
{
uint64_t max_timestamp = decoder->buf_timestamp;
/* Walk PSB+ packets when already in sync. */ staticint intel_pt_walk_psbend(struct intel_pt_decoder *decoder)
{ int err;
decoder->in_psb = true;
while (1) {
err = intel_pt_get_next_packet(decoder); if (err) goto out;
switch (decoder->packet.type) { case INTEL_PT_PSBEND:
err = 0; goto out;
case INTEL_PT_TIP_PGD: case INTEL_PT_TIP_PGE: case INTEL_PT_TIP: case INTEL_PT_TNT: case INTEL_PT_TRACESTOP: case INTEL_PT_BAD: case INTEL_PT_PSB: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD:
decoder->have_tma = false;
intel_pt_log("ERROR: Unexpected packet\n");
err = -EAGAIN; goto out;
case INTEL_PT_OVF:
err = intel_pt_overflow(decoder); goto out;
case INTEL_PT_TSC:
intel_pt_calc_tsc_timestamp(decoder); break;
case INTEL_PT_TMA:
intel_pt_calc_tma(decoder); break;
case INTEL_PT_CBR:
intel_pt_calc_cbr(decoder); break;
case INTEL_PT_MODE_EXEC:
intel_pt_mode_exec_status(decoder); break;
case INTEL_PT_PIP:
intel_pt_set_pip(decoder); break;
case INTEL_PT_FUP:
decoder->pge = true; if (decoder->packet.count) {
intel_pt_set_last_ip(decoder);
decoder->psb_ip = decoder->last_ip;
} break;
case INTEL_PT_MODE_TSX:
intel_pt_update_in_tx(decoder); break;
case INTEL_PT_MTC:
intel_pt_calc_mtc_timestamp(decoder); if (decoder->period_type == INTEL_PT_PERIOD_MTC)
decoder->state.type |= INTEL_PT_INSTRUCTION; break;
case INTEL_PT_CYC:
intel_pt_calc_cyc_timestamp(decoder); break;
case INTEL_PT_VMCS: case INTEL_PT_MNT: case INTEL_PT_PAD: default: break;
}
}
out:
decoder->in_psb = false;
return err;
}
staticint intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder)
{ int err;
while (1) {
err = intel_pt_get_next_packet(decoder); if (err) return err;
switch (decoder->packet.type) { case INTEL_PT_TNT: case INTEL_PT_FUP: case INTEL_PT_TRACESTOP: case INTEL_PT_PSB: case INTEL_PT_TSC: case INTEL_PT_TMA: case INTEL_PT_MODE_TSX: case INTEL_PT_BAD: case INTEL_PT_PSBEND: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD:
intel_pt_log("ERROR: Missing TIP after FUP\n");
decoder->pkt_state = INTEL_PT_STATE_ERR3;
decoder->pkt_step = 0; return -ENOENT;
case INTEL_PT_CBR:
intel_pt_calc_cbr(decoder); break;
case INTEL_PT_OVF: return intel_pt_overflow(decoder);
/* Lookahead and get the PIP, VMCS and TMA packets from PSB+ */ staticint intel_pt_vm_psb_lookahead_cb(struct intel_pt_pkt_info *pkt_info)
{ struct intel_pt_vm_tsc_info *data = pkt_info->data;
switch (pkt_info->packet.type) { case INTEL_PT_PAD: case INTEL_PT_MNT: case INTEL_PT_MODE_EXEC: case INTEL_PT_MODE_TSX: case INTEL_PT_MTC: case INTEL_PT_FUP: case INTEL_PT_CYC: case INTEL_PT_CBR: break;
case INTEL_PT_TSC:
data->tsc = true; break;
case INTEL_PT_TMA:
data->tma_packet = pkt_info->packet;
data->tma = true; break;
case INTEL_PT_PIP:
data->pip_packet = pkt_info->packet;
data->pip = true; break;
case INTEL_PT_VMCS:
data->vmcs_packet = pkt_info->packet;
data->vmcs = true; break;
case INTEL_PT_PSBEND:
data->psbend = true; return 1;
case INTEL_PT_TIP_PGE: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_OVF: case INTEL_PT_BAD: case INTEL_PT_TNT: case INTEL_PT_TIP_PGD: case INTEL_PT_TIP: case INTEL_PT_PSB: case INTEL_PT_TRACESTOP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD: default: return 1;
}
return 0;
}
struct intel_pt_ovf_fup_info { int max_lookahead; bool found;
};
/* Lookahead to detect a FUP packet after OVF */ staticint intel_pt_ovf_fup_lookahead_cb(struct intel_pt_pkt_info *pkt_info)
{ struct intel_pt_ovf_fup_info *data = pkt_info->data;
/* Lookahead and get the TMA packet after TSC */ staticint intel_pt_tma_lookahead_cb(struct intel_pt_pkt_info *pkt_info)
{ struct intel_pt_vm_tsc_info *data = pkt_info->data;
if (pkt_info->packet.type == INTEL_PT_CYC ||
pkt_info->packet.type == INTEL_PT_MTC) return !--(data->max_lookahead);
static uint64_t intel_pt_calc_expected_tsc(struct intel_pt_decoder *decoder,
uint32_t ctc,
uint32_t fc,
uint64_t last_ctc_timestamp,
uint64_t ctc_delta,
uint32_t last_ctc)
{ /* Number of CTC ticks from last_ctc_timestamp to last_mtc */
uint64_t last_mtc_ctc = last_ctc + ctc_delta; /* * Number of CTC ticks from there until current TMA packet. We would * expect last_mtc_ctc to be before ctc, but the TSC packet can slip * past an MTC, so a sign-extended value is used.
*/
uint64_t delta = (int16_t)((uint16_t)ctc - (uint16_t)last_mtc_ctc); /* Total CTC ticks from last_ctc_timestamp to current TMA packet */
uint64_t new_ctc_delta = ctc_delta + delta;
uint64_t expected_tsc;
/* * Convert CTC ticks to TSC ticks, add the starting point * (last_ctc_timestamp) and the fast counter from the TMA packet.
*/
expected_tsc = last_ctc_timestamp + intel_pt_ctc_to_tsc(decoder, new_ctc_delta) + fc;
/* VMX adds the TSC Offset, so subtract to get host TSC */
decoder->packet.payload -= vmcs_info->tsc_offset; /* TSC packet has only 7 bytes */
decoder->packet.payload &= SEVEN_BYTES;
/* * The buffer is mmapped from the data file, so this also updates the * data file.
*/ if (!decoder->vm_tm_corr_dry_run)
memcpy((void *)decoder->buf + 1, &decoder->packet.payload, 7);
/* Determine if TSC is from Host or Guest */ if (data->pip) { if (pip_in_vm(&data->pip_packet)) { /* Guest */ if (!vmcs_info) { /* PIP NR=1 without VMCS cannot happen */
p_log("ERROR: Missing VMCS");
intel_pt_translate_vm_tsc_offset(decoder, tsc_offset);
decoder->vm_tm_corr_reliable = false; return;
}
} else { /* Host */
decoder->last_reliable_timestamp = host_tsc;
decoder->vm_tm_corr_reliable = true; return;
}
} else { /* Host or Guest */
reliable = false; /* Host/Guest is a guess, so not reliable */ if (decoder->in_psb) { if (!tsc_offset) return; /* Zero TSC Offset, assume Host */ /* * TSC packet has only 7 bytes of TSC. We have no * information about the Guest's 8th byte, but it * doesn't matter because we only need 7 bytes. * Here, since the 8th byte is unreliable and * irrelevant, compare only 7 byes.
*/ if (vmcs_info &&
(tsc_offset & SEVEN_BYTES) ==
(vmcs_info->tsc_offset & SEVEN_BYTES)) { /* Same TSC Offset as last VMCS, assume Guest */ goto guest;
}
} /* * Check if the host_tsc is within the expected range. * Note, we could narrow the range more by looking ahead for * the next host TSC in the same buffer, but we don't bother to * do that because this is probably good enough.
*/ if (host_tsc >= expected_tsc && intel_pt_time_in_range(decoder, host_tsc)) { /* Within expected range for Host TSC, assume Host */
decoder->vm_tm_corr_reliable = false; return;
}
}
guest: /* Assuming Guest */
/* Determine whether to assign TSC Offset */ if (vmcs_info && vmcs_info->vmcs) { if (vmcs_info->tsc_offset && vmcs_info->reliable) {
assign = false;
} elseif (decoder->in_psb && data->pip && decoder->vm_tm_corr_reliable &&
decoder->vm_tm_corr_continuous && decoder->vm_tm_corr_same_buf) { /* Continuous tracing, TSC in a PSB is not a time loss */
assign = true;
assign_reliable = true;
} elseif (decoder->in_psb && data->pip && decoder->vm_tm_corr_same_buf) { /* * Unlikely to be a time loss TSC in a PSB which is not * at the start of a buffer.
*/
assign = true;
assign_reliable = false;
}
}
case INTEL_PT_TMA:
intel_pt_calc_tma(decoder); break;
case INTEL_PT_CYC:
intel_pt_calc_cyc_timestamp(decoder); break;
case INTEL_PT_CBR:
intel_pt_calc_cbr(decoder); break;
case INTEL_PT_PSBEND:
decoder->in_psb = false;
data.psbend = false; break;
case INTEL_PT_VMCS: if (decoder->packet.payload != NO_VMCS)
decoder->vmcs = decoder->packet.payload; break;
case INTEL_PT_BBP:
decoder->blk_type = decoder->packet.payload; break;
case INTEL_PT_BIP: if (decoder->blk_type == INTEL_PT_PEBS_BASIC &&
decoder->packet.count == 2)
intel_pt_vm_tm_corr_pebs_tsc(decoder); break;
case INTEL_PT_BEP: case INTEL_PT_BEP_IP:
decoder->blk_type = 0; break;
case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD: case INTEL_PT_MODE_EXEC: case INTEL_PT_MODE_TSX: case INTEL_PT_MNT: case INTEL_PT_PAD: case INTEL_PT_PTWRITE_IP: case INTEL_PT_PTWRITE: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_EXSTOP_IP: case INTEL_PT_EXSTOP: case INTEL_PT_PWRX: case INTEL_PT_BAD: /* Does not happen */ default: break;
}
}
/* Hop mode: Ignore TNT, do not walk code, but get ip from FUPs and TIPs */ staticint intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, int *err)
{
*err = 0;
/* Leap from PSB to PSB, getting ip from FUP within PSB+ */ if (decoder->leap && !decoder->in_psb && decoder->packet.type != INTEL_PT_PSB) {
*err = intel_pt_scan_for_psb(decoder); if (*err) return HOP_RETURN;
}
switch (decoder->packet.type) { case INTEL_PT_TNT: return HOP_IGNORE;
case INTEL_PT_BAD: case INTEL_PT_PAD: case INTEL_PT_TIP_PGE: case INTEL_PT_TSC: case INTEL_PT_TMA: case INTEL_PT_MODE_EXEC: case INTEL_PT_MODE_TSX: case INTEL_PT_MTC: case INTEL_PT_CYC: case INTEL_PT_VMCS: case INTEL_PT_PSBEND: case INTEL_PT_CBR: case INTEL_PT_TRACESTOP: case INTEL_PT_PIP: case INTEL_PT_OVF: case INTEL_PT_MNT: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD: default: return HOP_PROCESS;
}
}
/* Lookahead and get the FUP packet from PSB+ */ staticint intel_pt_psb_lookahead_cb(struct intel_pt_pkt_info *pkt_info)
{ struct intel_pt_psb_info *data = pkt_info->data;
switch (pkt_info->packet.type) { case INTEL_PT_PAD: case INTEL_PT_MNT: case INTEL_PT_TSC: case INTEL_PT_TMA: case INTEL_PT_MODE_EXEC: case INTEL_PT_MODE_TSX: case INTEL_PT_MTC: case INTEL_PT_CYC: case INTEL_PT_VMCS: case INTEL_PT_CBR: case INTEL_PT_PIP: if (data->after_psbend) {
data->after_psbend -= 1; if (!data->after_psbend) return 1;
} break;
case INTEL_PT_FUP: if (data->after_psbend) return 1; if (data->fup || pkt_info->packet.count == 0) return 1;
data->fup_packet = pkt_info->packet;
data->fup = true; break;
case INTEL_PT_PSBEND: if (!data->fup) return 1; /* Keep going to check for a TIP.PGE */
data->after_psbend = 6; break;
case INTEL_PT_TIP_PGE: /* Ignore FUP in PSB+ if followed by TIP.PGE */ if (data->after_psbend)
data->fup = false; return 1;
case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD: if (data->after_psbend) {
data->after_psbend -= 1; if (!data->after_psbend) return 1; break;
} return 1;
case INTEL_PT_OVF: case INTEL_PT_BAD: case INTEL_PT_TNT: case INTEL_PT_TIP_PGD: case INTEL_PT_TIP: case INTEL_PT_PSB: case INTEL_PT_TRACESTOP: default: return 1;
}
return 0;
}
staticint intel_pt_psb(struct intel_pt_decoder *decoder)
{ int err;
case INTEL_PT_PSB:
decoder->state.psb_offset = decoder->pos;
decoder->psb_ip = 0; if (intel_pt_psb_with_fup(decoder, &err)) return err;
err = intel_pt_psb(decoder); if (err == -EAGAIN) goto next; return err;
case INTEL_PT_PIP:
intel_pt_update_pip(decoder); break;
case INTEL_PT_MTC:
intel_pt_calc_mtc_timestamp(decoder); if (decoder->period_type != INTEL_PT_PERIOD_MTC) break; /* * Ensure that there has been an instruction since the * last MTC.
*/ if (!decoder->mtc_insn) break;
decoder->mtc_insn = false; /* Ensure that there is a timestamp */ if (!decoder->timestamp) break;
decoder->state.type = INTEL_PT_INSTRUCTION;
decoder->state.from_ip = decoder->ip;
decoder->state.to_ip = 0;
decoder->mtc_insn = false; return 0;
case INTEL_PT_TSC:
intel_pt_calc_tsc_timestamp(decoder); break;
case INTEL_PT_TMA:
intel_pt_calc_tma(decoder); break;
case INTEL_PT_CYC:
intel_pt_calc_cyc_timestamp(decoder); break;
case INTEL_PT_CBR:
intel_pt_calc_cbr(decoder); if (decoder->cbr != decoder->cbr_seen) {
decoder->state.type = 0; return 0;
} break;
case INTEL_PT_MODE_EXEC:
intel_pt_mode_exec(decoder);
err = intel_pt_get_next_packet(decoder); if (err) return err; if (decoder->packet.type == INTEL_PT_FUP) {
decoder->set_fup_mode_exec = true;
no_tip = true;
} goto next;
case INTEL_PT_MODE_TSX: /* MODE_TSX need not be followed by FUP */ if (!decoder->pge || decoder->in_psb) {
intel_pt_update_in_tx(decoder); break;
}
err = intel_pt_mode_tsx(decoder, &no_tip); if (err) return err; goto next;
case INTEL_PT_BAD: /* Does not happen */ return intel_pt_bug(decoder);
case INTEL_PT_PSBEND: case INTEL_PT_VMCS: case INTEL_PT_MNT: case INTEL_PT_PAD: break;
case INTEL_PT_PTWRITE_IP:
decoder->fup_ptw_payload = decoder->packet.payload;
err = intel_pt_get_next_packet(decoder); if (err) return err; if (decoder->packet.type == INTEL_PT_FUP) {
decoder->set_fup_ptw = true;
no_tip = true;
} else {
intel_pt_log_at("ERROR: Missing FUP after PTWRITE",
decoder->pos);
} goto next;
/* Walk PSB+ packets to get in sync. */ staticint intel_pt_walk_psb(struct intel_pt_decoder *decoder)
{ int err;
decoder->in_psb = true;
while (1) {
err = intel_pt_get_next_packet(decoder); if (err) goto out;
switch (decoder->packet.type) { case INTEL_PT_TIP_PGD:
decoder->continuous_period = false;
fallthrough; case INTEL_PT_TIP_PGE: case INTEL_PT_TIP: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD:
intel_pt_log("ERROR: Unexpected packet\n");
err = -ENOENT; goto out;
case INTEL_PT_FUP:
decoder->pge = true; if (intel_pt_have_ip(decoder)) {
uint64_t current_ip = decoder->ip;
case INTEL_PT_TNT: case INTEL_PT_PSBEND: case INTEL_PT_VMCS: case INTEL_PT_MNT: case INTEL_PT_PAD: case INTEL_PT_PTWRITE: case INTEL_PT_PTWRITE_IP: case INTEL_PT_EXSTOP: case INTEL_PT_EXSTOP_IP: case INTEL_PT_MWAIT: case INTEL_PT_PWRE: case INTEL_PT_PWRX: case INTEL_PT_BBP: case INTEL_PT_BIP: case INTEL_PT_BEP: case INTEL_PT_BEP_IP: case INTEL_PT_CFE: case INTEL_PT_CFE_IP: case INTEL_PT_EVD: default: break;
}
}
}
staticint intel_pt_sync_ip(struct intel_pt_decoder *decoder)
{ int err;
if (!decoder->branch_enable) {
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
decoder->state.type = 0; /* Do not have a sample */ return 0;
}
intel_pt_log("Scanning for full IP\n");
err = intel_pt_walk_to_ip(decoder); if (err || ((decoder->state.type & INTEL_PT_PSB_EVT) && !decoder->ip)) return err;
/* In hop mode, resample to get the to_ip as an "instruction" sample */ if (decoder->hop)
decoder->pkt_state = INTEL_PT_STATE_RESAMPLE; else
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
if (decoder->ip) { /* * In hop mode, resample to get the PSB FUP ip as an * "instruction" sample.
*/ if (decoder->hop)
decoder->pkt_state = INTEL_PT_STATE_RESAMPLE; else
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
}
/** * intel_pt_next_psb - move buffer pointer to the start of the next PSB packet. * @buf: pointer to buffer pointer * @len: size of buffer * * Updates the buffer pointer to point to the start of the next PSB packet if * there is one, otherwise the buffer pointer is unchanged. If @buf is updated, * @len is adjusted accordingly. * * Return: %true if a PSB packet is found, %false otherwise.
*/ staticbool intel_pt_next_psb(unsignedchar **buf, size_t *len)
{ unsignedchar *next;
next = memmem(*buf, *len, INTEL_PT_PSB_STR, INTEL_PT_PSB_LEN); if (next) {
*len -= next - *buf;
*buf = next; returntrue;
} returnfalse;
}
/** * intel_pt_step_psb - move buffer pointer to the start of the following PSB * packet. * @buf: pointer to buffer pointer * @len: size of buffer * * Updates the buffer pointer to point to the start of the following PSB packet * (skipping the PSB at @buf itself) if there is one, otherwise the buffer * pointer is unchanged. If @buf is updated, @len is adjusted accordingly. * * Return: %true if a PSB packet is found, %false otherwise.
*/ staticbool intel_pt_step_psb(unsignedchar **buf, size_t *len)
{ unsignedchar *next;
if (!*len) returnfalse;
next = memmem(*buf + 1, *len - 1, INTEL_PT_PSB_STR, INTEL_PT_PSB_LEN); if (next) {
*len -= next - *buf;
*buf = next; returntrue;
} returnfalse;
}
/** * intel_pt_last_psb - find the last PSB packet in a buffer. * @buf: buffer * @len: size of buffer * * This function finds the last PSB in a buffer. * * Return: A pointer to the last PSB in @buf if found, %NULL otherwise.
*/ staticunsignedchar *intel_pt_last_psb(unsignedchar *buf, size_t len)
{ constchar *n = INTEL_PT_PSB_STR; unsignedchar *p;
size_t k;
if (len < INTEL_PT_PSB_LEN) return NULL;
k = len - INTEL_PT_PSB_LEN + 1; while (1) {
p = memrchr(buf, n[0], k); if (!p) return NULL; if (!memcmp(p + 1, n + 1, INTEL_PT_PSB_LEN - 1)) return p;
k = p - buf; if (!k) return NULL;
}
}
/** * intel_pt_next_tsc - find and return next TSC. * @buf: buffer * @len: size of buffer * @tsc: TSC value returned * @rem: returns remaining size when TSC is found * * Find a TSC packet in @buf and return the TSC value. This function assumes * that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a * PSBEND packet is found. * * Return: %true if TSC is found, false otherwise.
*/ staticbool intel_pt_next_tsc(unsignedchar *buf, size_t len, uint64_t *tsc,
size_t *rem)
{ enum intel_pt_pkt_ctx ctx = INTEL_PT_NO_CTX; struct intel_pt_pkt packet; int ret;
while (len) {
ret = intel_pt_get_packet(buf, len, &packet, &ctx); if (ret <= 0) returnfalse; if (packet.type == INTEL_PT_TSC) {
*tsc = packet.payload;
*rem = len; returntrue;
} if (packet.type == INTEL_PT_PSBEND) returnfalse;
buf += ret;
len -= ret;
} returnfalse;
}
/** * intel_pt_tsc_cmp - compare 7-byte TSCs. * @tsc1: first TSC to compare * @tsc2: second TSC to compare * * This function compares 7-byte TSC values allowing for the possibility that * TSC wrapped around. Generally it is not possible to know if TSC has wrapped * around so for that purpose this function assumes the absolute difference is * less than half the maximum difference. * * Return: %-1 if @tsc1 is before @tsc2, %0 if @tsc1 == @tsc2, %1 if @tsc1 is * after @tsc2.
*/ staticint intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2)
{ const uint64_t halfway = (1ULL << 55);
/** * adj_for_padding - adjust overlap to account for padding. * @buf_b: second buffer * @buf_a: first buffer * @len_a: size of first buffer * * @buf_a might have up to 7 bytes of padding appended. Adjust the overlap * accordingly. * * Return: A pointer into @buf_b from where non-overlapped data starts
*/ staticunsignedchar *adj_for_padding(unsignedchar *buf_b, unsignedchar *buf_a, size_t len_a)
{ unsignedchar *p = buf_b - MAX_PADDING; unsignedchar *q = buf_a + len_a - MAX_PADDING; int i;
for (i = MAX_PADDING; i; i--, p++, q++) { if (*p != *q) break;
}
return p;
}
/** * intel_pt_find_overlap_tsc - determine start of non-overlapped trace data * using TSC. * @buf_a: first buffer * @len_a: size of first buffer * @buf_b: second buffer * @len_b: size of second buffer * @consecutive: returns true if there is data in buf_b that is consecutive * to buf_a * @ooo_tsc: out-of-order TSC due to VM TSC offset / scaling * * If the trace contains TSC we can look at the last TSC of @buf_a and the * first TSC of @buf_b in order to determine if the buffers overlap, and then * walk forward in @buf_b until a later TSC is found. A precondition is that * @buf_a and @buf_b are positioned at a PSB. * * Return: A pointer into @buf_b from where non-overlapped data starts, or * @buf_b + @len_b if there is no non-overlapped data.
*/ staticunsignedchar *intel_pt_find_overlap_tsc(unsignedchar *buf_a,
size_t len_a, unsignedchar *buf_b,
size_t len_b, bool *consecutive, bool ooo_tsc)
{
uint64_t tsc_a, tsc_b; unsignedchar *p;
size_t len, rem_a, rem_b;
p = intel_pt_last_psb(buf_a, len_a); if (!p) return buf_b; /* No PSB in buf_a => no overlap */
len = len_a - (p - buf_a); if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) { /* The last PSB+ in buf_a is incomplete, so go back one more */
len_a -= len;
p = intel_pt_last_psb(buf_a, len_a); if (!p) return buf_b; /* No full PSB+ => assume no overlap */
len = len_a - (p - buf_a); if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) return buf_b; /* No TSC in buf_a => assume no overlap */
}
while (1) { /* Ignore PSB+ with no TSC */ if (intel_pt_next_tsc(buf_b, len_b, &tsc_b, &rem_b)) { int cmp = intel_pt_tsc_cmp(tsc_a, tsc_b);
/* Same TSC, so buffers are consecutive */ if (!cmp && rem_b >= rem_a) { unsignedchar *start;
if (!intel_pt_step_psb(&buf_b, &len_b)) return buf_b + len_b; /* No PSB in buf_b => no data */
}
}
/** * intel_pt_find_overlap - determine start of non-overlapped trace data. * @buf_a: first buffer * @len_a: size of first buffer * @buf_b: second buffer * @len_b: size of second buffer * @have_tsc: can use TSC packets to detect overlap * @consecutive: returns true if there is data in buf_b that is consecutive * to buf_a * @ooo_tsc: out-of-order TSC due to VM TSC offset / scaling * * When trace samples or snapshots are recorded there is the possibility that * the data overlaps. Note that, for the purposes of decoding, data is only * useful if it begins with a PSB packet. * * Return: A pointer into @buf_b from where non-overlapped data starts, or * @buf_b + @len_b if there is no non-overlapped data.
*/ unsignedchar *intel_pt_find_overlap(unsignedchar *buf_a, size_t len_a, unsignedchar *buf_b, size_t len_b, bool have_tsc, bool *consecutive, bool ooo_tsc)
{ unsignedchar *found;
/* Buffer 'b' must start at PSB so throw away everything before that */ if (!intel_pt_next_psb(&buf_b, &len_b)) return buf_b + len_b; /* No PSB */
if (!intel_pt_next_psb(&buf_a, &len_a)) return buf_b; /* No overlap */
if (have_tsc) {
found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b,
consecutive, ooo_tsc); if (found) return found;
}
/* * Buffer 'b' cannot end within buffer 'a' so, for comparison purposes, * we can ignore the first part of buffer 'a'.
*/ while (len_b < len_a) { if (!intel_pt_step_psb(&buf_a, &len_a)) return buf_b; /* No overlap */
}
/* Now len_b >= len_a */ while (1) { /* Potential overlap so check the bytes */
found = memmem(buf_a, len_a, buf_b, len_a); if (found) {
*consecutive = true; return adj_for_padding(buf_b + len_a, buf_a, len_a);
}
/* Try again at next PSB in buffer 'a' */ if (!intel_pt_step_psb(&buf_a, &len_a)) return buf_b; /* No overlap */
}
}
/** * struct fast_forward_data - data used by intel_pt_ff_cb(). * @timestamp: timestamp to fast forward towards * @buf_timestamp: buffer timestamp of last buffer with trace data earlier than * the fast forward timestamp.
*/ struct fast_forward_data {
uint64_t timestamp;
uint64_t buf_timestamp;
};
/** * intel_pt_ff_cb - fast forward lookahead callback. * @buffer: Intel PT trace buffer * @data: opaque pointer to fast forward data (struct fast_forward_data) * * Determine if @buffer trace is past the fast forward timestamp. * * Return: 1 (stop lookahead) if @buffer trace is past the fast forward * timestamp, and 0 otherwise.
*/ staticint intel_pt_ff_cb(struct intel_pt_buffer *buffer, void *data)
{ struct fast_forward_data *d = data; unsignedchar *buf;
uint64_t tsc;
size_t rem;
size_t len;
buf = (unsignedchar *)buffer->buf;
len = buffer->len;
if (!intel_pt_next_psb(&buf, &len) ||
!intel_pt_next_tsc(buf, len, &tsc, &rem)) return 0;
/* * If the buffer contains a timestamp earlier that the fast forward * timestamp, then record it, else stop.
*/ if (tsc < d->timestamp)
d->buf_timestamp = buffer->ref_timestamp; else return 1;
return 0;
}
/** * intel_pt_fast_forward - reposition decoder forwards. * @decoder: Intel PT decoder * @timestamp: timestamp to fast forward towards * * Reposition decoder at the last PSB with a timestamp earlier than @timestamp. * * Return: 0 on success or negative error code on failure.
*/ int intel_pt_fast_forward(struct intel_pt_decoder *decoder, uint64_t timestamp)
{ struct fast_forward_data d = { .timestamp = timestamp }; unsignedchar *buf;
size_t len; int err;
intel_pt_log("Fast forward towards timestamp " x64_fmt "\n", timestamp);
/* Find buffer timestamp of buffer to fast forward to */
err = decoder->lookahead(decoder->data, intel_pt_ff_cb, &d); if (err < 0) return err;
/* Walk to buffer with same buffer timestamp */ if (d.buf_timestamp) { do {
decoder->pos += decoder->len;
decoder->len = 0;
err = intel_pt_get_next_data(decoder, true); /* -ENOLINK means non-consecutive trace */ if (err && err != -ENOLINK) return err;
} while (decoder->buf_timestamp != d.buf_timestamp);
}
if (!decoder->buf) return 0;
buf = (unsignedchar *)decoder->buf;
len = decoder->len;
if (!intel_pt_next_psb(&buf, &len)) return 0;
/* * Walk PSBs while the PSB timestamp is less than the fast forward * timestamp.
*/ do {
uint64_t tsc;
size_t rem;
if (!intel_pt_next_tsc(buf, len, &tsc, &rem)) break;
tsc = intel_pt_8b_tsc(tsc, decoder->buf_timestamp); /* * A TSC packet can slip past MTC packets but, after fast * forward, decoding starts at the TSC timestamp. That means * the timestamps may not be exactly the same as the timestamps * that would have been decoded without fast forward.
*/ if (tsc < timestamp) {
intel_pt_log("Fast forward to next PSB timestamp " x64_fmt "\n", tsc);
decoder->pos += decoder->len - len;
decoder->buf = buf;
decoder->len = len;
intel_pt_reposition(decoder);
} else { break;
}
} while (intel_pt_step_psb(&buf, &len));
return 0;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.80 Sekunden
(vorverarbeitet am 2026-04-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.