diff options
author | Sven Schnelle <svens@stackframe.org> | 2019-07-23 16:37:52 -0400 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2019-08-03 02:56:57 -0400 |
commit | 52a22e6c27be9089fdd9c4e1857939f0dec8f57c (patch) | |
tree | 760e141459f496f85115018ed325878598f41c0e /arch/parisc | |
parent | d562aca37a543cc3de85be6a6946771a27d50c6a (diff) |
parisc/ftrace: Add KPROBES_ON_FTRACE
Allow KPROBES to use the ftrace infrastructure on PA-RISC.
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Signed-off-by: Helge Deller <deller@gmx.de>
Diffstat (limited to 'arch/parisc')
-rw-r--r-- | arch/parisc/Kconfig | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/entry.S | 99 | ||||
-rw-r--r-- | arch/parisc/kernel/ftrace.c | 58 |
3 files changed, 156 insertions, 3 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 6d732e451071..ee59171edffe 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -61,6 +61,8 @@ config PARISC | |||
61 | select HAVE_KRETPROBES | 61 | select HAVE_KRETPROBES |
62 | select HAVE_DYNAMIC_FTRACE if $(cc-option,-fpatchable-function-entry=1,1) | 62 | select HAVE_DYNAMIC_FTRACE if $(cc-option,-fpatchable-function-entry=1,1) |
63 | select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE | 63 | select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE |
64 | select HAVE_KPROBES_ON_FTRACE | ||
65 | select HAVE_DYNAMIC_FTRACE_WITH_REGS | ||
64 | 66 | ||
65 | help | 67 | help |
66 | The PA-RISC microprocessor is designed by Hewlett-Packard and used | 68 | The PA-RISC microprocessor is designed by Hewlett-Packard and used |
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index d9d3387f7c47..1d1d748c227f 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S | |||
@@ -1996,6 +1996,7 @@ _mcount: | |||
1996 | * calling mcount(), and 2 instructions for ftrace_stub(). That way we | 1996 | * calling mcount(), and 2 instructions for ftrace_stub(). That way we |
1997 | * have all on one L1 cacheline. | 1997 | * have all on one L1 cacheline. |
1998 | */ | 1998 | */ |
1999 | ldi 0, %arg3 | ||
1999 | b ftrace_function_trampoline | 2000 | b ftrace_function_trampoline |
2000 | copy %r3, %arg2 /* caller original %sp */ | 2001 | copy %r3, %arg2 /* caller original %sp */ |
2001 | ftrace_stub: | 2002 | ftrace_stub: |
@@ -2048,6 +2049,7 @@ ftrace_caller: | |||
2048 | LDREG 0(%r3), %r25 | 2049 | LDREG 0(%r3), %r25 |
2049 | copy %rp, %r26 | 2050 | copy %rp, %r26 |
2050 | ldo -8(%r25), %r25 | 2051 | ldo -8(%r25), %r25 |
2052 | ldi 0, %r23 /* no pt_regs */ | ||
2051 | b,l ftrace_function_trampoline, %rp | 2053 | b,l ftrace_function_trampoline, %rp |
2052 | copy %r3, %r24 | 2054 | copy %r3, %r24 |
2053 | 2055 | ||
@@ -2075,6 +2077,103 @@ ftrace_caller: | |||
2075 | 2077 | ||
2076 | ENDPROC_CFI(ftrace_caller) | 2078 | ENDPROC_CFI(ftrace_caller) |
2077 | 2079 | ||
2080 | #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS | ||
2081 | ENTRY_CFI(ftrace_regs_caller,caller,frame=FTRACE_FRAME_SIZE+PT_SZ_ALGN, | ||
2082 | CALLS,SAVE_RP,SAVE_SP) | ||
2083 | ftrace_regs_caller: | ||
2084 | .global ftrace_regs_caller | ||
2085 | |||
2086 | ldo -FTRACE_FRAME_SIZE(%sp), %r1 | ||
2087 | STREG %rp, -RP_OFFSET(%r1) | ||
2088 | |||
2089 | copy %sp, %r1 | ||
2090 | ldo PT_SZ_ALGN(%sp), %sp | ||
2091 | |||
2092 | STREG %rp, PT_GR2(%r1) | ||
2093 | STREG %r3, PT_GR3(%r1) | ||
2094 | STREG %r4, PT_GR4(%r1) | ||
2095 | STREG %r5, PT_GR5(%r1) | ||
2096 | STREG %r6, PT_GR6(%r1) | ||
2097 | STREG %r7, PT_GR7(%r1) | ||
2098 | STREG %r8, PT_GR8(%r1) | ||
2099 | STREG %r9, PT_GR9(%r1) | ||
2100 | STREG %r10, PT_GR10(%r1) | ||
2101 | STREG %r11, PT_GR11(%r1) | ||
2102 | STREG %r12, PT_GR12(%r1) | ||
2103 | STREG %r13, PT_GR13(%r1) | ||
2104 | STREG %r14, PT_GR14(%r1) | ||
2105 | STREG %r15, PT_GR15(%r1) | ||
2106 | STREG %r16, PT_GR16(%r1) | ||
2107 | STREG %r17, PT_GR17(%r1) | ||
2108 | STREG %r18, PT_GR18(%r1) | ||
2109 | STREG %r19, PT_GR19(%r1) | ||
2110 | STREG %r20, PT_GR20(%r1) | ||
2111 | STREG %r21, PT_GR21(%r1) | ||
2112 | STREG %r22, PT_GR22(%r1) | ||
2113 | STREG %r23, PT_GR23(%r1) | ||
2114 | STREG %r24, PT_GR24(%r1) | ||
2115 | STREG %r25, PT_GR25(%r1) | ||
2116 | STREG %r26, PT_GR26(%r1) | ||
2117 | STREG %r27, PT_GR27(%r1) | ||
2118 | STREG %r28, PT_GR28(%r1) | ||
2119 | STREG %r29, PT_GR29(%r1) | ||
2120 | STREG %r30, PT_GR30(%r1) | ||
2121 | STREG %r31, PT_GR31(%r1) | ||
2122 | mfctl %cr11, %r26 | ||
2123 | STREG %r26, PT_SAR(%r1) | ||
2124 | |||
2125 | copy %rp, %r26 | ||
2126 | LDREG -FTRACE_FRAME_SIZE-PT_SZ_ALGN(%sp), %r25 | ||
2127 | ldo -8(%r25), %r25 | ||
2128 | copy %r3, %arg2 | ||
2129 | b,l ftrace_function_trampoline, %rp | ||
2130 | copy %r1, %arg3 /* struct pt_regs */ | ||
2131 | |||
2132 | ldo -PT_SZ_ALGN(%sp), %r1 | ||
2133 | |||
2134 | LDREG PT_SAR(%r1), %rp | ||
2135 | mtctl %rp, %cr11 | ||
2136 | |||
2137 | LDREG PT_GR2(%r1), %rp | ||
2138 | LDREG PT_GR3(%r1), %r3 | ||
2139 | LDREG PT_GR4(%r1), %r4 | ||
2140 | LDREG PT_GR5(%r1), %r5 | ||
2141 | LDREG PT_GR6(%r1), %r6 | ||
2142 | LDREG PT_GR7(%r1), %r7 | ||
2143 | LDREG PT_GR8(%r1), %r8 | ||
2144 | LDREG PT_GR9(%r1), %r9 | ||
2145 | LDREG PT_GR10(%r1),%r10 | ||
2146 | LDREG PT_GR11(%r1),%r11 | ||
2147 | LDREG PT_GR12(%r1),%r12 | ||
2148 | LDREG PT_GR13(%r1),%r13 | ||
2149 | LDREG PT_GR14(%r1),%r14 | ||
2150 | LDREG PT_GR15(%r1),%r15 | ||
2151 | LDREG PT_GR16(%r1),%r16 | ||
2152 | LDREG PT_GR17(%r1),%r17 | ||
2153 | LDREG PT_GR18(%r1),%r18 | ||
2154 | LDREG PT_GR19(%r1),%r19 | ||
2155 | LDREG PT_GR20(%r1),%r20 | ||
2156 | LDREG PT_GR21(%r1),%r21 | ||
2157 | LDREG PT_GR22(%r1),%r22 | ||
2158 | LDREG PT_GR23(%r1),%r23 | ||
2159 | LDREG PT_GR24(%r1),%r24 | ||
2160 | LDREG PT_GR25(%r1),%r25 | ||
2161 | LDREG PT_GR26(%r1),%r26 | ||
2162 | LDREG PT_GR27(%r1),%r27 | ||
2163 | LDREG PT_GR28(%r1),%r28 | ||
2164 | LDREG PT_GR29(%r1),%r29 | ||
2165 | LDREG PT_GR30(%r1),%r30 | ||
2166 | LDREG PT_GR31(%r1),%r31 | ||
2167 | |||
2168 | ldo -PT_SZ_ALGN(%sp), %sp | ||
2169 | LDREGM -FTRACE_FRAME_SIZE(%sp), %r1 | ||
2170 | /* Adjust return point to jump back to beginning of traced function */ | ||
2171 | ldo -4(%r1), %r1 | ||
2172 | bv,n (%r1) | ||
2173 | |||
2174 | ENDPROC_CFI(ftrace_regs_caller) | ||
2175 | |||
2176 | #endif | ||
2078 | #endif | 2177 | #endif |
2079 | 2178 | ||
2080 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 2179 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c index 23ce416787ac..b836fc61a24f 100644 --- a/arch/parisc/kernel/ftrace.c +++ b/arch/parisc/kernel/ftrace.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/ftrace.h> | 14 | #include <linux/ftrace.h> |
15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
16 | #include <linux/kprobes.h> | ||
17 | #include <linux/ptrace.h> | ||
16 | 18 | ||
17 | #include <asm/assembly.h> | 19 | #include <asm/assembly.h> |
18 | #include <asm/sections.h> | 20 | #include <asm/sections.h> |
@@ -48,7 +50,8 @@ static void __hot prepare_ftrace_return(unsigned long *parent, | |||
48 | 50 | ||
49 | void notrace __hot ftrace_function_trampoline(unsigned long parent, | 51 | void notrace __hot ftrace_function_trampoline(unsigned long parent, |
50 | unsigned long self_addr, | 52 | unsigned long self_addr, |
51 | unsigned long org_sp_gr3) | 53 | unsigned long org_sp_gr3, |
54 | struct pt_regs *regs) | ||
52 | { | 55 | { |
53 | #ifndef CONFIG_DYNAMIC_FTRACE | 56 | #ifndef CONFIG_DYNAMIC_FTRACE |
54 | extern ftrace_func_t ftrace_trace_function; | 57 | extern ftrace_func_t ftrace_trace_function; |
@@ -58,11 +61,11 @@ void notrace __hot ftrace_function_trampoline(unsigned long parent, | |||
58 | if (function_trace_op->flags & FTRACE_OPS_FL_ENABLED && | 61 | if (function_trace_op->flags & FTRACE_OPS_FL_ENABLED && |
59 | ftrace_trace_function != ftrace_stub) | 62 | ftrace_trace_function != ftrace_stub) |
60 | ftrace_trace_function(self_addr, parent, | 63 | ftrace_trace_function(self_addr, parent, |
61 | function_trace_op, NULL); | 64 | function_trace_op, regs); |
62 | 65 | ||
63 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 66 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
64 | if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub || | 67 | if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub || |
65 | ftrace_graph_entry != ftrace_graph_entry_stub) { | 68 | ftrace_graph_entry != ftrace_graph_entry_stub) { |
66 | unsigned long *parent_rp; | 69 | unsigned long *parent_rp; |
67 | 70 | ||
68 | /* calculate pointer to %rp in stack */ | 71 | /* calculate pointer to %rp in stack */ |
@@ -100,6 +103,12 @@ int ftrace_update_ftrace_func(ftrace_func_t func) | |||
100 | return 0; | 103 | return 0; |
101 | } | 104 | } |
102 | 105 | ||
106 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, | ||
107 | unsigned long addr) | ||
108 | { | ||
109 | return 0; | ||
110 | } | ||
111 | |||
103 | unsigned long ftrace_call_adjust(unsigned long addr) | 112 | unsigned long ftrace_call_adjust(unsigned long addr) |
104 | { | 113 | { |
105 | return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4; | 114 | return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4; |
@@ -191,3 +200,46 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | |||
191 | return 0; | 200 | return 0; |
192 | } | 201 | } |
193 | #endif | 202 | #endif |
203 | |||
204 | #ifdef CONFIG_KPROBES_ON_FTRACE | ||
205 | void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, | ||
206 | struct ftrace_ops *ops, struct pt_regs *regs) | ||
207 | { | ||
208 | struct kprobe_ctlblk *kcb; | ||
209 | struct kprobe *p = get_kprobe((kprobe_opcode_t *)ip); | ||
210 | |||
211 | if (unlikely(!p) || kprobe_disabled(p)) | ||
212 | return; | ||
213 | |||
214 | if (kprobe_running()) { | ||
215 | kprobes_inc_nmissed_count(p); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | __this_cpu_write(current_kprobe, p); | ||
220 | |||
221 | kcb = get_kprobe_ctlblk(); | ||
222 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | ||
223 | |||
224 | regs->iaoq[0] = ip; | ||
225 | regs->iaoq[1] = ip + 4; | ||
226 | |||
227 | if (!p->pre_handler || !p->pre_handler(p, regs)) { | ||
228 | regs->iaoq[0] = ip + 4; | ||
229 | regs->iaoq[1] = ip + 8; | ||
230 | |||
231 | if (unlikely(p->post_handler)) { | ||
232 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
233 | p->post_handler(p, regs, 0); | ||
234 | } | ||
235 | } | ||
236 | __this_cpu_write(current_kprobe, NULL); | ||
237 | } | ||
238 | NOKPROBE_SYMBOL(kprobe_ftrace_handler); | ||
239 | |||
240 | int arch_prepare_kprobe_ftrace(struct kprobe *p) | ||
241 | { | ||
242 | p->ainsn.insn = NULL; | ||
243 | return 0; | ||
244 | } | ||
245 | #endif | ||