Skip to content

Commit

Permalink
perf intel-pt: Fix "Unexpected indirect branch" error
Browse files Browse the repository at this point in the history
Some Atom CPUs can produce FUP packets that contain NLIP (next linear
instruction pointer) instead of CLIP (current linear instruction
pointer).  That will result in "Unexpected indirect branch" errors. Fix
by comparing IP to NLIP in that case.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/1527762225-26024-5-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Adrian Hunter authored and Arnaldo Carvalho de Melo committed Jun 6, 2018
1 parent dd27b87 commit 9fb5233
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
17 changes: 15 additions & 2 deletions tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ struct intel_pt_decoder {
bool have_cyc;
bool fixup_last_mtc;
bool have_last_ip;
enum intel_pt_param_flags flags;
uint64_t pos;
uint64_t last_ip;
uint64_t ip;
Expand Down Expand Up @@ -226,6 +227,8 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params)
decoder->return_compression = params->return_compression;
decoder->branch_enable = params->branch_enable;

decoder->flags = params->flags;

decoder->period = params->period;
decoder->period_type = params->period_type;

Expand Down Expand Up @@ -1097,6 +1100,15 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
return ret;
}

static inline bool intel_pt_fup_with_nlip(struct intel_pt_decoder *decoder,
struct intel_pt_insn *intel_pt_insn,
uint64_t ip, int err)
{
return decoder->flags & INTEL_PT_FUP_WITH_NLIP && !err &&
intel_pt_insn->branch == INTEL_PT_BR_INDIRECT &&
ip == decoder->ip + intel_pt_insn->length;
}

static int intel_pt_walk_fup(struct intel_pt_decoder *decoder)
{
struct intel_pt_insn intel_pt_insn;
Expand All @@ -1109,10 +1121,11 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder)
err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip);
if (err == INTEL_PT_RETURN)
return 0;
if (err == -EAGAIN) {
if (err == -EAGAIN ||
intel_pt_fup_with_nlip(decoder, &intel_pt_insn, ip, err)) {
if (intel_pt_fup_event(decoder))
return 0;
return err;
return -EAGAIN;
}
decoder->set_fup_tx_flags = false;
if (err)
Expand Down
9 changes: 9 additions & 0 deletions tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ enum {
INTEL_PT_ERR_MAX,
};

enum intel_pt_param_flags {
/*
* FUP packet can contain next linear instruction pointer instead of
* current linear instruction pointer.
*/
INTEL_PT_FUP_WITH_NLIP = 1 << 0,
};

struct intel_pt_state {
enum intel_pt_sample_type type;
int err;
Expand Down Expand Up @@ -106,6 +114,7 @@ struct intel_pt_params {
unsigned int mtc_period;
uint32_t tsc_ctc_ratio_n;
uint32_t tsc_ctc_ratio_d;
enum intel_pt_param_flags flags;
};

struct intel_pt_decoder;
Expand Down
4 changes: 4 additions & 0 deletions tools/perf/util/intel-pt.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
unsigned int queue_nr)
{
struct intel_pt_params params = { .get_trace = 0, };
struct perf_env *env = pt->machine->env;
struct intel_pt_queue *ptq;

ptq = zalloc(sizeof(struct intel_pt_queue));
Expand Down Expand Up @@ -830,6 +831,9 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
}
}

if (env->cpuid && !strncmp(env->cpuid, "GenuineIntel,6,92,", 18))
params.flags |= INTEL_PT_FUP_WITH_NLIP;

ptq->decoder = intel_pt_decoder_new(&params);
if (!ptq->decoder)
goto out_free;
Expand Down

0 comments on commit 9fb5233

Please sign in to comment.