aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_event_intel_lbr.c
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2014-11-04 21:56:11 -0500
committerIngo Molnar <mingo@kernel.org>2015-02-18 11:16:14 -0500
commitaa54ae9b87b83af7edabcc34a299e7e014609af4 (patch)
tree97f9dcd94f98cf444b2fa498e19e3c5cb20c238c /arch/x86/kernel/cpu/perf_event_intel_lbr.c
parent2c70d0086e4e9e2440f0f78098090f32bde14277 (diff)
perf/x86/intel: Discard zero length call entries in LBR call stack
"Zero length call" uses the attribute of the call instruction to push the immediate instruction pointer on to the stack and then pops off that address into a register. This is accomplished without any matching return instruction. It confuses the hardware and make the recorded call stack incorrect. We can partially resolve this issue by: decode call instructions and discard any zero length call entry in the LBR stack. Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com> Signed-off-by: Kan Liang <kan.liang@intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul Mackerras <paulus@samba.org> Cc: eranian@google.com Cc: jolsa@redhat.com Link: http://lkml.kernel.org/r/1415156173-10035-16-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event_intel_lbr.c')
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_lbr.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index 92a44fdbc9d3..084f2eb20c8b 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -94,7 +94,8 @@ enum {
94 X86_BR_ABORT = 1 << 12,/* transaction abort */ 94 X86_BR_ABORT = 1 << 12,/* transaction abort */
95 X86_BR_IN_TX = 1 << 13,/* in transaction */ 95 X86_BR_IN_TX = 1 << 13,/* in transaction */
96 X86_BR_NO_TX = 1 << 14,/* not in transaction */ 96 X86_BR_NO_TX = 1 << 14,/* not in transaction */
97 X86_BR_CALL_STACK = 1 << 15,/* call stack */ 97 X86_BR_ZERO_CALL = 1 << 15,/* zero length call */
98 X86_BR_CALL_STACK = 1 << 16,/* call stack */
98}; 99};
99 100
100#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL) 101#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
@@ -111,13 +112,15 @@ enum {
111 X86_BR_JMP |\ 112 X86_BR_JMP |\
112 X86_BR_IRQ |\ 113 X86_BR_IRQ |\
113 X86_BR_ABORT |\ 114 X86_BR_ABORT |\
114 X86_BR_IND_CALL) 115 X86_BR_IND_CALL |\
116 X86_BR_ZERO_CALL)
115 117
116#define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY) 118#define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY)
117 119
118#define X86_BR_ANY_CALL \ 120#define X86_BR_ANY_CALL \
119 (X86_BR_CALL |\ 121 (X86_BR_CALL |\
120 X86_BR_IND_CALL |\ 122 X86_BR_IND_CALL |\
123 X86_BR_ZERO_CALL |\
121 X86_BR_SYSCALL |\ 124 X86_BR_SYSCALL |\
122 X86_BR_IRQ |\ 125 X86_BR_IRQ |\
123 X86_BR_INT) 126 X86_BR_INT)
@@ -702,6 +705,12 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
702 ret = X86_BR_INT; 705 ret = X86_BR_INT;
703 break; 706 break;
704 case 0xe8: /* call near rel */ 707 case 0xe8: /* call near rel */
708 insn_get_immediate(&insn);
709 if (insn.immediate1.value == 0) {
710 /* zero length call */
711 ret = X86_BR_ZERO_CALL;
712 break;
713 }
705 case 0x9a: /* call far absolute */ 714 case 0x9a: /* call far absolute */
706 ret = X86_BR_CALL; 715 ret = X86_BR_CALL;
707 break; 716 break;