From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933516AbbFJMva (ORCPT ); Wed, 10 Jun 2015 08:51:30 -0400 Received: from mga01.intel.com ([192.55.52.88]:29181 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754163AbbFJMvL (ORCPT ); Wed, 10 Jun 2015 08:51:11 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,587,1427785200"; d="scan'208";a="740786149" From: Adrian Hunter To: Arnaldo Carvalho de Melo Cc: linux-kernel@vger.kernel.org, Jiri Olsa Subject: [PATCH 2/2] perf tools: Fix Intel PT getting stuck in a loop Date: Wed, 10 Jun 2015 15:42:43 +0300 Message-Id: <1433940163-23949-3-git-send-email-adrian.hunter@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1433940163-23949-1-git-send-email-adrian.hunter@intel.com> References: <1433940163-23949-1-git-send-email-adrian.hunter@intel.com> Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- .../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