perf, x86: Robustify PEBS fixup
It turns out the LBR is massively unreliable on certain CPUs, so code the fixup a little more defensive to avoid crashing the kernel. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: paulus@samba.org Cc: eranian@google.com Cc: robert.richter@amd.com Cc: fweisbec@gmail.com LKML-Reference: <20100305154129.042271287@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
74846d35b2
commit
a562b1871f
@ -399,10 +399,23 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
if (!x86_pmu.intel_cap.pebs_trap)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* No LBR entry, no basic block, no rewinding
|
||||
*/
|
||||
if (!cpuc->lbr_stack.nr || !from || !to)
|
||||
return 0;
|
||||
|
||||
if (ip < to)
|
||||
/*
|
||||
* Basic blocks should never cross user/kernel boundaries
|
||||
*/
|
||||
if (kernel_ip(ip) != kernel_ip(to))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* unsigned math, either ip is before the start (impossible) or
|
||||
* the basic block is larger than 1 page (sanity)
|
||||
*/
|
||||
if ((ip - to) > PAGE_SIZE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -420,7 +433,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
|
||||
old_to = to;
|
||||
if (!kernel_ip(ip)) {
|
||||
int bytes, size = min_t(int, MAX_INSN_SIZE, ip - to);
|
||||
int bytes, size = MAX_INSN_SIZE;
|
||||
|
||||
bytes = copy_from_user_nmi(buf, (void __user *)to, size);
|
||||
if (bytes != size)
|
||||
@ -440,6 +453,10 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Even though we decoded the basic block, the instruction stream
|
||||
* never matched the given IP, either the TO or the IP got corrupted.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user