diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/include/asm/ftrace.h | 57 | ||||
-rw-r--r-- | arch/mips/kernel/ftrace.c | 56 | ||||
-rw-r--r-- | arch/mips/kernel/mcount.S | 8 |
3 files changed, 106 insertions, 15 deletions
diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h index 7094a40b96d8..3986cd8704f3 100644 --- a/arch/mips/include/asm/ftrace.h +++ b/arch/mips/include/asm/ftrace.h | |||
@@ -19,6 +19,62 @@ | |||
19 | extern void _mcount(void); | 19 | extern void _mcount(void); |
20 | #define mcount _mcount | 20 | #define mcount _mcount |
21 | 21 | ||
22 | #define safe_load(load, src, dst, error) \ | ||
23 | do { \ | ||
24 | asm volatile ( \ | ||
25 | "1: " load " %[" STR(dst) "], 0(%[" STR(src) "])\n"\ | ||
26 | " li %[" STR(error) "], 0\n" \ | ||
27 | "2:\n" \ | ||
28 | \ | ||
29 | ".section .fixup, \"ax\"\n" \ | ||
30 | "3: li %[" STR(error) "], 1\n" \ | ||
31 | " j 2b\n" \ | ||
32 | ".previous\n" \ | ||
33 | \ | ||
34 | ".section\t__ex_table,\"a\"\n\t" \ | ||
35 | STR(PTR) "\t1b, 3b\n\t" \ | ||
36 | ".previous\n" \ | ||
37 | \ | ||
38 | : [dst] "=&r" (dst), [error] "=r" (error)\ | ||
39 | : [src] "r" (src) \ | ||
40 | : "memory" \ | ||
41 | ); \ | ||
42 | } while (0) | ||
43 | |||
44 | #define safe_store(store, src, dst, error) \ | ||
45 | do { \ | ||
46 | asm volatile ( \ | ||
47 | "1: " store " %[" STR(src) "], 0(%[" STR(dst) "])\n"\ | ||
48 | " li %[" STR(error) "], 0\n" \ | ||
49 | "2:\n" \ | ||
50 | \ | ||
51 | ".section .fixup, \"ax\"\n" \ | ||
52 | "3: li %[" STR(error) "], 1\n" \ | ||
53 | " j 2b\n" \ | ||
54 | ".previous\n" \ | ||
55 | \ | ||
56 | ".section\t__ex_table,\"a\"\n\t"\ | ||
57 | STR(PTR) "\t1b, 3b\n\t" \ | ||
58 | ".previous\n" \ | ||
59 | \ | ||
60 | : [error] "=r" (error) \ | ||
61 | : [dst] "r" (dst), [src] "r" (src)\ | ||
62 | : "memory" \ | ||
63 | ); \ | ||
64 | } while (0) | ||
65 | |||
66 | #define safe_load_code(dst, src, error) \ | ||
67 | safe_load(STR(lw), src, dst, error) | ||
68 | #define safe_store_code(src, dst, error) \ | ||
69 | safe_store(STR(sw), src, dst, error) | ||
70 | |||
71 | #define safe_load_stack(dst, src, error) \ | ||
72 | safe_load(STR(PTR_L), src, dst, error) | ||
73 | |||
74 | #define safe_store_stack(src, dst, error) \ | ||
75 | safe_store(STR(PTR_S), src, dst, error) | ||
76 | |||
77 | |||
22 | #ifdef CONFIG_DYNAMIC_FTRACE | 78 | #ifdef CONFIG_DYNAMIC_FTRACE |
23 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | 79 | static inline unsigned long ftrace_call_adjust(unsigned long addr) |
24 | { | 80 | { |
@@ -27,6 +83,7 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) | |||
27 | 83 | ||
28 | struct dyn_arch_ftrace { | 84 | struct dyn_arch_ftrace { |
29 | }; | 85 | }; |
86 | |||
30 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 87 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
31 | #endif /* __ASSEMBLY__ */ | 88 | #endif /* __ASSEMBLY__ */ |
32 | #endif /* CONFIG_FUNCTION_TRACER */ | 89 | #endif /* CONFIG_FUNCTION_TRACER */ |
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index e981a497c98f..e363fc69aabd 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c | |||
@@ -27,7 +27,13 @@ static unsigned int ftrace_nop = 0x00000000; | |||
27 | 27 | ||
28 | static int ftrace_modify_code(unsigned long ip, unsigned int new_code) | 28 | static int ftrace_modify_code(unsigned long ip, unsigned int new_code) |
29 | { | 29 | { |
30 | *(unsigned int *)ip = new_code; | 30 | int faulted; |
31 | |||
32 | /* *(unsigned int *)ip = new_code; */ | ||
33 | safe_store_code(new_code, ip, faulted); | ||
34 | |||
35 | if (unlikely(faulted)) | ||
36 | return -EFAULT; | ||
31 | 37 | ||
32 | flush_icache_range(ip, ip + 8); | 38 | flush_icache_range(ip, ip + 8); |
33 | 39 | ||
@@ -41,14 +47,20 @@ int ftrace_make_nop(struct module *mod, | |||
41 | struct dyn_ftrace *rec, unsigned long addr) | 47 | struct dyn_ftrace *rec, unsigned long addr) |
42 | { | 48 | { |
43 | unsigned int new; | 49 | unsigned int new; |
50 | int faulted; | ||
44 | unsigned long ip = rec->ip; | 51 | unsigned long ip = rec->ip; |
45 | 52 | ||
46 | /* We have compiled module with -mlong-calls, but compiled the kernel | 53 | /* We have compiled module with -mlong-calls, but compiled the kernel |
47 | * without it, we need to cope with them respectively. */ | 54 | * without it, we need to cope with them respectively. */ |
48 | if (ip & 0x40000000) { | 55 | if (ip & 0x40000000) { |
49 | /* record it for ftrace_make_call */ | 56 | /* record it for ftrace_make_call */ |
50 | if (lui_v1 == 0) | 57 | if (lui_v1 == 0) { |
51 | lui_v1 = *(unsigned int *)ip; | 58 | /* lui_v1 = *(unsigned int *)ip; */ |
59 | safe_load_code(lui_v1, ip, faulted); | ||
60 | |||
61 | if (unlikely(faulted)) | ||
62 | return -EFAULT; | ||
63 | } | ||
52 | 64 | ||
53 | /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) | 65 | /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) |
54 | * addiu v1, v1, low_16bit_of_mcount | 66 | * addiu v1, v1, low_16bit_of_mcount |
@@ -147,6 +159,7 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, | |||
147 | { | 159 | { |
148 | unsigned long sp, ip, ra; | 160 | unsigned long sp, ip, ra; |
149 | unsigned int code; | 161 | unsigned int code; |
162 | int faulted; | ||
150 | 163 | ||
151 | /* in module or kernel? */ | 164 | /* in module or kernel? */ |
152 | if (self_addr & 0x40000000) { | 165 | if (self_addr & 0x40000000) { |
@@ -162,8 +175,11 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, | |||
162 | do { | 175 | do { |
163 | ip -= 4; | 176 | ip -= 4; |
164 | 177 | ||
165 | /* get the code at "ip" */ | 178 | /* get the code at "ip": code = *(unsigned int *)ip; */ |
166 | code = *(unsigned int *)ip; | 179 | safe_load_code(code, ip, faulted); |
180 | |||
181 | if (unlikely(faulted)) | ||
182 | return 0; | ||
167 | 183 | ||
168 | /* If we hit the non-store instruction before finding where the | 184 | /* If we hit the non-store instruction before finding where the |
169 | * ra is stored, then this is a leaf function and it does not | 185 | * ra is stored, then this is a leaf function and it does not |
@@ -174,11 +190,14 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, | |||
174 | } while (((code & S_RA_SP) != S_RA_SP)); | 190 | } while (((code & S_RA_SP) != S_RA_SP)); |
175 | 191 | ||
176 | sp = fp + (code & OFFSET_MASK); | 192 | sp = fp + (code & OFFSET_MASK); |
177 | ra = *(unsigned long *)sp; | 193 | |
194 | /* ra = *(unsigned long *)sp; */ | ||
195 | safe_load_stack(ra, sp, faulted); | ||
196 | if (unlikely(faulted)) | ||
197 | return 0; | ||
178 | 198 | ||
179 | if (ra == parent) | 199 | if (ra == parent) |
180 | return sp; | 200 | return sp; |
181 | |||
182 | return 0; | 201 | return 0; |
183 | } | 202 | } |
184 | 203 | ||
@@ -193,6 +212,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
193 | struct ftrace_graph_ent trace; | 212 | struct ftrace_graph_ent trace; |
194 | unsigned long return_hooker = (unsigned long) | 213 | unsigned long return_hooker = (unsigned long) |
195 | &return_to_handler; | 214 | &return_to_handler; |
215 | int faulted; | ||
196 | 216 | ||
197 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | 217 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) |
198 | return; | 218 | return; |
@@ -206,21 +226,23 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
206 | * ftrace_get_parent_addr() does it! | 226 | * ftrace_get_parent_addr() does it! |
207 | */ | 227 | */ |
208 | 228 | ||
209 | old = *parent; | 229 | /* old = *parent; */ |
230 | safe_load_stack(old, parent, faulted); | ||
231 | if (unlikely(faulted)) | ||
232 | goto out; | ||
210 | 233 | ||
211 | parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old, | 234 | parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old, |
212 | (unsigned long)parent, | 235 | (unsigned long)parent, |
213 | fp); | 236 | fp); |
214 | |||
215 | /* If fails when getting the stack address of the non-leaf function's | 237 | /* If fails when getting the stack address of the non-leaf function's |
216 | * ra, stop function graph tracer and return */ | 238 | * ra, stop function graph tracer and return */ |
217 | if (parent == 0) { | 239 | if (parent == 0) |
218 | ftrace_graph_stop(); | 240 | goto out; |
219 | WARN_ON(1); | ||
220 | return; | ||
221 | } | ||
222 | 241 | ||
223 | *parent = return_hooker; | 242 | /* *parent = return_hooker; */ |
243 | safe_store_stack(return_hooker, parent, faulted); | ||
244 | if (unlikely(faulted)) | ||
245 | goto out; | ||
224 | 246 | ||
225 | if (ftrace_push_return_trace(old, self_addr, &trace.depth, fp) == | 247 | if (ftrace_push_return_trace(old, self_addr, &trace.depth, fp) == |
226 | -EBUSY) { | 248 | -EBUSY) { |
@@ -235,5 +257,9 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
235 | current->curr_ret_stack--; | 257 | current->curr_ret_stack--; |
236 | *parent = old; | 258 | *parent = old; |
237 | } | 259 | } |
260 | return; | ||
261 | out: | ||
262 | ftrace_graph_stop(); | ||
263 | WARN_ON(1); | ||
238 | } | 264 | } |
239 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 265 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 98d469032506..bdfef2c24f16 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S | |||
@@ -139,7 +139,15 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra) | |||
139 | #endif | 139 | #endif |
140 | PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */ | 140 | PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */ |
141 | jal prepare_ftrace_return | 141 | jal prepare_ftrace_return |
142 | #ifdef CONFIG_FRAME_POINTER | ||
142 | move a2, fp /* arg3: frame pointer */ | 143 | move a2, fp /* arg3: frame pointer */ |
144 | #else | ||
145 | #ifdef CONFIG_64BIT | ||
146 | PTR_LA a2, PT_SIZE(sp) | ||
147 | #else | ||
148 | PTR_LA a2, (PT_SIZE+8)(sp) | ||
149 | #endif | ||
150 | #endif | ||
143 | 151 | ||
144 | MCOUNT_RESTORE_REGS | 152 | MCOUNT_RESTORE_REGS |
145 | RETURN_BACK | 153 | RETURN_BACK |