aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/perf_event.h12
-rw-r--r--arch/powerpc/kernel/misc.S26
-rw-r--r--arch/sparc/include/asm/perf_event.h8
-rw-r--r--arch/sparc/kernel/helpers.S6
-rw-r--r--arch/x86/include/asm/perf_event.h13
-rw-r--r--arch/x86/include/asm/stacktrace.h7
-rw-r--r--arch/x86/kernel/cpu/perf_event.c16
-rw-r--r--include/linux/perf_event.h32
-rw-r--r--include/trace/ftrace.h2
-rw-r--r--kernel/perf_event.c5
-rw-r--r--kernel/trace/trace_event_perf.c2
11 files changed, 46 insertions, 83 deletions
diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event.h
index e6d4ce69b126..5c16b891d501 100644
--- a/arch/powerpc/include/asm/perf_event.h
+++ b/arch/powerpc/include/asm/perf_event.h
@@ -21,3 +21,15 @@
21#ifdef CONFIG_FSL_EMB_PERF_EVENT 21#ifdef CONFIG_FSL_EMB_PERF_EVENT
22#include <asm/perf_event_fsl_emb.h> 22#include <asm/perf_event_fsl_emb.h>
23#endif 23#endif
24
25#ifdef CONFIG_PERF_EVENTS
26#include <asm/ptrace.h>
27#include <asm/reg.h>
28
29#define perf_arch_fetch_caller_regs(regs, __ip) \
30 do { \
31 (regs)->nip = __ip; \
32 (regs)->gpr[1] = *(unsigned long *)__get_SP(); \
33 asm volatile("mfmsr %0" : "=r" ((regs)->msr)); \
34 } while (0)
35#endif
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
index 22e507c8a556..2d29752cbe16 100644
--- a/arch/powerpc/kernel/misc.S
+++ b/arch/powerpc/kernel/misc.S
@@ -127,29 +127,3 @@ _GLOBAL(__setup_cpu_power7)
127_GLOBAL(__restore_cpu_power7) 127_GLOBAL(__restore_cpu_power7)
128 /* place holder */ 128 /* place holder */
129 blr 129 blr
130
131/*
132 * Get a minimal set of registers for our caller's nth caller.
133 * r3 = regs pointer, r5 = n.
134 *
135 * We only get R1 (stack pointer), NIP (next instruction pointer)
136 * and LR (link register). These are all we can get in the
137 * general case without doing complicated stack unwinding, but
138 * fortunately they are enough to do a stack backtrace, which
139 * is all we need them for.
140 */
141_GLOBAL(perf_arch_fetch_caller_regs)
142 mr r6,r1
143 cmpwi r5,0
144 mflr r4
145 ble 2f
146 mtctr r5
1471: PPC_LL r6,0(r6)
148 bdnz 1b
149 PPC_LL r4,PPC_LR_STKOFF(r6)
1502: PPC_LL r7,0(r6)
151 PPC_LL r7,PPC_LR_STKOFF(r7)
152 PPC_STL r6,GPR1-STACK_FRAME_OVERHEAD(r3)
153 PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3)
154 PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3)
155 blr
diff --git a/arch/sparc/include/asm/perf_event.h b/arch/sparc/include/asm/perf_event.h
index 7e2669894ce8..74c4e0cd889c 100644
--- a/arch/sparc/include/asm/perf_event.h
+++ b/arch/sparc/include/asm/perf_event.h
@@ -6,7 +6,15 @@ extern void set_perf_event_pending(void);
6#define PERF_EVENT_INDEX_OFFSET 0 6#define PERF_EVENT_INDEX_OFFSET 0
7 7
8#ifdef CONFIG_PERF_EVENTS 8#ifdef CONFIG_PERF_EVENTS
9#include <asm/ptrace.h>
10
9extern void init_hw_perf_events(void); 11extern void init_hw_perf_events(void);
12
13extern void
14__perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
15
16#define perf_arch_fetch_caller_regs(pt_regs, ip) \
17 __perf_arch_fetch_caller_regs(pt_regs, ip, 1);
10#else 18#else
11static inline void init_hw_perf_events(void) { } 19static inline void init_hw_perf_events(void) { }
12#endif 20#endif
diff --git a/arch/sparc/kernel/helpers.S b/arch/sparc/kernel/helpers.S
index 92090cc9e829..682fee06a16b 100644
--- a/arch/sparc/kernel/helpers.S
+++ b/arch/sparc/kernel/helpers.S
@@ -47,9 +47,9 @@ stack_trace_flush:
47 .size stack_trace_flush,.-stack_trace_flush 47 .size stack_trace_flush,.-stack_trace_flush
48 48
49#ifdef CONFIG_PERF_EVENTS 49#ifdef CONFIG_PERF_EVENTS
50 .globl perf_arch_fetch_caller_regs 50 .globl __perf_arch_fetch_caller_regs
51 .type perf_arch_fetch_caller_regs,#function 51 .type __perf_arch_fetch_caller_regs,#function
52perf_arch_fetch_caller_regs: 52__perf_arch_fetch_caller_regs:
53 /* We always read the %pstate into %o5 since we will use 53 /* We always read the %pstate into %o5 since we will use
54 * that to construct a fake %tstate to store into the regs. 54 * that to construct a fake %tstate to store into the regs.
55 */ 55 */
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 254883d0c7e0..02de29830ffe 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -140,6 +140,19 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
140extern unsigned long perf_misc_flags(struct pt_regs *regs); 140extern unsigned long perf_misc_flags(struct pt_regs *regs);
141#define perf_misc_flags(regs) perf_misc_flags(regs) 141#define perf_misc_flags(regs) perf_misc_flags(regs)
142 142
143#include <asm/stacktrace.h>
144
145/*
146 * We abuse bit 3 from flags to pass exact information, see perf_misc_flags
147 * and the comment with PERF_EFLAGS_EXACT.
148 */
149#define perf_arch_fetch_caller_regs(regs, __ip) { \
150 (regs)->ip = (__ip); \
151 (regs)->bp = caller_frame_pointer(); \
152 (regs)->cs = __KERNEL_CS; \
153 regs->flags = 0; \
154}
155
143#else 156#else
144static inline void init_hw_perf_events(void) { } 157static inline void init_hw_perf_events(void) { }
145static inline void perf_events_lapic_init(void) { } 158static inline void perf_events_lapic_init(void) { }
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
index a957463d3c7a..2b16a2ad23dc 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -78,17 +78,14 @@ struct stack_frame_ia32 {
78 u32 return_address; 78 u32 return_address;
79}; 79};
80 80
81static inline unsigned long rewind_frame_pointer(int n) 81static inline unsigned long caller_frame_pointer(void)
82{ 82{
83 struct stack_frame *frame; 83 struct stack_frame *frame;
84 84
85 get_bp(frame); 85 get_bp(frame);
86 86
87#ifdef CONFIG_FRAME_POINTER 87#ifdef CONFIG_FRAME_POINTER
88 while (n--) { 88 frame = frame->next_frame;
89 if (probe_kernel_address(&frame->next_frame, frame))
90 break;
91 }
92#endif 89#endif
93 90
94 return (unsigned long)frame; 91 return (unsigned long)frame;
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 9632fb61e8f9..2c075fe573d0 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1706,22 +1706,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
1706 return entry; 1706 return entry;
1707} 1707}
1708 1708
1709void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
1710{
1711 regs->ip = ip;
1712 /*
1713 * perf_arch_fetch_caller_regs adds another call, we need to increment
1714 * the skip level
1715 */
1716 regs->bp = rewind_frame_pointer(skip + 1);
1717 regs->cs = __KERNEL_CS;
1718 /*
1719 * We abuse bit 3 to pass exact information, see perf_misc_flags
1720 * and the comment with PERF_EFLAGS_EXACT.
1721 */
1722 regs->flags = 0;
1723}
1724
1725unsigned long perf_instruction_pointer(struct pt_regs *regs) 1709unsigned long perf_instruction_pointer(struct pt_regs *regs)
1726{ 1710{
1727 unsigned long ip; 1711 unsigned long ip;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fb6c91eac7e3..bea785cef493 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -905,8 +905,10 @@ extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
905 905
906extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); 906extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
907 907
908extern void 908#ifndef perf_arch_fetch_caller_regs
909perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip); 909static inline void
910perf_arch_fetch_caller_regs(struct regs *regs, unsigned long ip) { }
911#endif
910 912
911/* 913/*
912 * Take a snapshot of the regs. Skip ip and frame pointer to 914 * Take a snapshot of the regs. Skip ip and frame pointer to
@@ -916,31 +918,11 @@ perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
916 * - bp for callchains 918 * - bp for callchains
917 * - eflags, for future purposes, just in case 919 * - eflags, for future purposes, just in case
918 */ 920 */
919static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip) 921static inline void perf_fetch_caller_regs(struct pt_regs *regs)
920{ 922{
921 unsigned long ip;
922
923 memset(regs, 0, sizeof(*regs)); 923 memset(regs, 0, sizeof(*regs));
924 924
925 switch (skip) { 925 perf_arch_fetch_caller_regs(regs, CALLER_ADDR0);
926 case 1 :
927 ip = CALLER_ADDR0;
928 break;
929 case 2 :
930 ip = CALLER_ADDR1;
931 break;
932 case 3 :
933 ip = CALLER_ADDR2;
934 break;
935 case 4:
936 ip = CALLER_ADDR3;
937 break;
938 /* No need to support further for now */
939 default:
940 ip = 0;
941 }
942
943 return perf_arch_fetch_caller_regs(regs, ip, skip);
944} 926}
945 927
946static inline void 928static inline void
@@ -950,7 +932,7 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
950 struct pt_regs hot_regs; 932 struct pt_regs hot_regs;
951 933
952 if (!regs) { 934 if (!regs) {
953 perf_fetch_caller_regs(&hot_regs, 1); 935 perf_fetch_caller_regs(&hot_regs);
954 regs = &hot_regs; 936 regs = &hot_regs;
955 } 937 }
956 __perf_sw_event(event_id, nr, nmi, regs, addr); 938 __perf_sw_event(event_id, nr, nmi, regs, addr);
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 3d685d1f2a03..8ee8b6e6b25e 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -705,7 +705,7 @@ perf_trace_##call(void *__data, proto) \
705 int __data_size; \ 705 int __data_size; \
706 int rctx; \ 706 int rctx; \
707 \ 707 \
708 perf_fetch_caller_regs(&__regs, 1); \ 708 perf_fetch_caller_regs(&__regs); \
709 \ 709 \
710 __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ 710 __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
711 __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ 711 __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index e099650cd249..9ae4dbcdf469 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -2851,11 +2851,6 @@ __weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
2851 return NULL; 2851 return NULL;
2852} 2852}
2853 2853
2854__weak
2855void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
2856{
2857}
2858
2859 2854
2860/* 2855/*
2861 * We assume there is only KVM supporting the callbacks. 2856 * We assume there is only KVM supporting the callbacks.
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index cb6f365016e4..21db1d3a48d0 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -9,8 +9,6 @@
9#include <linux/kprobes.h> 9#include <linux/kprobes.h>
10#include "trace.h" 10#include "trace.h"
11 11
12EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
13
14static char *perf_trace_buf[4]; 12static char *perf_trace_buf[4];
15 13
16/* 14/*