perf intel-pt: Enable decoder to handle TIP.PGD with missing IP
[cascardo/linux.git] / tools / perf / util / intel-pt-decoder / intel-pt-decoder.c
index 8ff6c6a..7591a0c 100644 (file)
@@ -80,6 +80,7 @@ struct intel_pt_decoder {
        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);
        void *data;
        struct intel_pt_state state;
        const unsigned char *buf;
@@ -186,6 +187,7 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params)
 
        decoder->get_trace          = params->get_trace;
        decoder->walk_insn          = params->walk_insn;
+       decoder->pgd_ip             = params->pgd_ip;
        decoder->data               = params->data;
        decoder->return_compression = params->return_compression;
 
@@ -1008,6 +1010,19 @@ static int intel_pt_walk_tip(struct intel_pt_decoder *decoder)
        int err;
 
        err = intel_pt_walk_insn(decoder, &intel_pt_insn, 0);
+       if (err == INTEL_PT_RETURN &&
+           decoder->pgd_ip &&
+           decoder->pkt_state == INTEL_PT_STATE_TIP_PGD &&
+           (decoder->state.type & INTEL_PT_BRANCH) &&
+           decoder->pgd_ip(decoder->state.to_ip, decoder->data)) {
+               /* Unconditional branch leaving filter region */
+               decoder->no_progress = 0;
+               decoder->pge = false;
+               decoder->continuous_period = false;
+               decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
+               decoder->state.to_ip = 0;
+               return 0;
+       }
        if (err == INTEL_PT_RETURN)
                return 0;
        if (err)
@@ -1036,6 +1051,21 @@ static int intel_pt_walk_tip(struct intel_pt_decoder *decoder)
        }
 
        if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) {
+               uint64_t to_ip = decoder->ip + intel_pt_insn.length +
+                                intel_pt_insn.rel;
+
+               if (decoder->pgd_ip &&
+                   decoder->pkt_state == INTEL_PT_STATE_TIP_PGD &&
+                   decoder->pgd_ip(to_ip, decoder->data)) {
+                       /* Conditional branch leaving filter region */
+                       decoder->pge = false;
+                       decoder->continuous_period = false;
+                       decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
+                       decoder->ip = to_ip;
+                       decoder->state.from_ip = decoder->ip;
+                       decoder->state.to_ip = 0;
+                       return 0;
+               }
                intel_pt_log_at("ERROR: Conditional branch when expecting indirect branch",
                                decoder->ip);
                decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;