diff options
-rw-r--r-- | arch/powerpc/include/asm/perf_event.h | 12 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc.S | 26 | ||||
-rw-r--r-- | arch/sparc/include/asm/perf_event.h | 8 | ||||
-rw-r--r-- | arch/sparc/kernel/helpers.S | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/perf_event.h | 13 | ||||
-rw-r--r-- | arch/x86/include/asm/stacktrace.h | 7 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 16 | ||||
-rw-r--r-- | include/linux/perf_event.h | 32 | ||||
-rw-r--r-- | include/trace/ftrace.h | 2 | ||||
-rw-r--r-- | kernel/perf_event.c | 5 | ||||
-rw-r--r-- | kernel/trace/trace_event_perf.c | 2 |
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 | ||
147 | 1: PPC_LL r6,0(r6) | ||
148 | bdnz 1b | ||
149 | PPC_LL r4,PPC_LR_STKOFF(r6) | ||
150 | 2: 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 | |||
9 | extern void init_hw_perf_events(void); | 11 | extern void init_hw_perf_events(void); |
12 | |||
13 | extern 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 |
11 | static inline void init_hw_perf_events(void) { } | 19 | static 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 |
52 | perf_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); | |||
140 | extern unsigned long perf_misc_flags(struct pt_regs *regs); | 140 | extern 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 |
144 | static inline void init_hw_perf_events(void) { } | 157 | static inline void init_hw_perf_events(void) { } |
145 | static inline void perf_events_lapic_init(void) { } | 158 | static 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 | ||
81 | static inline unsigned long rewind_frame_pointer(int n) | 81 | static 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 | ||
1709 | void 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 | |||
1725 | unsigned long perf_instruction_pointer(struct pt_regs *regs) | 1709 | unsigned 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 | ||
906 | extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); | 906 | extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); |
907 | 907 | ||
908 | extern void | 908 | #ifndef perf_arch_fetch_caller_regs |
909 | perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip); | 909 | static inline void |
910 | perf_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 | */ |
919 | static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip) | 921 | static 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 | ||
946 | static inline void | 928 | static 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 | ||
2855 | void 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 | ||
12 | EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs); | ||
13 | |||
14 | static char *perf_trace_buf[4]; | 12 | static char *perf_trace_buf[4]; |
15 | 13 | ||
16 | /* | 14 | /* |