Check for being stuck in a loop.  That 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.  The only way to be in a loop
that consumes no packets is if it consists of unconditional
branches.  So the check for being stuck is if we see
a repeating cycle of consecutive unconditional branches.

Signed-off-by: Adrian Hunter <[email protected]>
---
 .../perf/util/intel-pt-decoder/intel-pt-decoder.c  | 42 ++++++++++++++++++++++
 .../perf/util/intel-pt-decoder/intel-pt-decoder.h  |  1 +
 2 files changed, 43 insertions(+)

diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c 
b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 748a7a078313..e8ff6573ecec 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -37,6 +37,9 @@
 
 #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];
@@ -114,6 +117,10 @@ struct intel_pt_decoder {
        unsigned int fup_tx_flags;
        unsigned int tx_flags;
        uint64_t timestamp_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];
@@ -263,6 +270,8 @@ static int intel_pt_ext_err(int code)
                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;
        }
@@ -278,6 +287,7 @@ static const char *intel_pt_err_msgs[] = {
        [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)
@@ -550,6 +560,7 @@ static int intel_pt_walk_insn(struct intel_pt_decoder 
*decoder,
        decoder->period_insn_cnt += insn_cnt;
 
        if (err) {
+               decoder->no_progress = 0;
                decoder->pkt_state = INTEL_PT_STATE_ERR2;
                intel_pt_log_at("ERROR: Failed to get instruction",
                                decoder->ip);
@@ -589,13 +600,44 @@ static int intel_pt_walk_insn(struct intel_pt_decoder 
*decoder,
        }
 
        if (intel_pt_insn->branch == INTEL_PT_BR_UNCONDITIONAL) {
+               int cnt = decoder->no_progress++;
+
                decoder->state.from_ip = decoder->ip;
                decoder->ip += intel_pt_insn->length +
                                intel_pt_insn->rel;
                decoder->state.to_ip = decoder->ip;
                err = INTEL_PT_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;
+                       } else if (cnt > INTEL_PT_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;
+                       } else if (!--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;
 
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h 
b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
index 955263adfd8d..706c6bccc57e 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
@@ -48,6 +48,7 @@ enum {
        INTEL_PT_ERR_OVR,
        INTEL_PT_ERR_LOST,
        INTEL_PT_ERR_UNK,
+       INTEL_PT_ERR_NELOOP,
        INTEL_PT_ERR_MAX,
 };
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to