aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2012-04-30 16:20:23 -0400
committerSteven Rostedt <rostedt@goodmis.org>2012-07-19 13:20:03 -0400
commit08f6fba503111e0336f2b4d6915a4a18f9b60e51 (patch)
tree119f971348614154552b70fb5cbe358f7c532a18
parent28fb5dfa783c25dbeeb25a72663f8066a3a517f5 (diff)
ftrace/x86: Add separate function to save regs
Add a way to have different functions calling different trampolines. If a ftrace_ops wants regs saved on the return, then have only the functions with ops registered to save regs. Functions registered by other ops would not be affected, unless the functions overlap. If one ftrace_ops registered functions A, B and C and another ops registered fucntions to save regs on A, and D, then only functions A and D would be saving regs. Function B and C would work as normal. Although A is registered by both ops: normal and saves regs; this is fine as saving the regs is needed to satisfy one of the ops that calls it but the regs are ignored by the other ops function. x86_64 implements the full regs saving, and i386 just passes a NULL for regs to satisfy the ftrace_ops passing. Where an arch must supply both regs and ftrace_ops parameters, even if regs is just NULL. It is OK for an arch to pass NULL regs. All function trace users that require regs passing must add the flag FTRACE_OPS_FL_SAVE_REGS when registering the ftrace_ops. If the arch does not support saving regs then the ftrace_ops will fail to register. The flag FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED may be set that will prevent the ftrace_ops from failing to register. In this case, the handler may either check if regs is not NULL or check if ARCH_SUPPORTS_FTRACE_SAVE_REGS. If the arch supports passing regs it will set this macro and pass regs for ops that request them. All other archs will just pass NULL. Link: Link: http://lkml.kernel.org/r/20120711195745.107705970@goodmis.org Cc: Alexander van Heukelum <heukelum@fastmail.fm> Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--arch/x86/include/asm/ftrace.h47
-rw-r--r--arch/x86/kernel/entry_32.S4
-rw-r--r--arch/x86/kernel/entry_64.S94
-rw-r--r--arch/x86/kernel/ftrace.c77
-rw-r--r--include/linux/ftrace.h107
-rw-r--r--kernel/trace/ftrace.c91
6 files changed, 373 insertions, 47 deletions
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index b3bb1f3f2773..a8475014c4ad 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -3,27 +3,33 @@
3 3
4#ifdef __ASSEMBLY__ 4#ifdef __ASSEMBLY__
5 5
6 .macro MCOUNT_SAVE_FRAME 6 /* skip is set if the stack was already partially adjusted */
7 /* taken from glibc */ 7 .macro MCOUNT_SAVE_FRAME skip=0
8 subq $0x38, %rsp 8 /*
9 movq %rax, (%rsp) 9 * We add enough stack to save all regs.
10 movq %rcx, 8(%rsp) 10 */
11 movq %rdx, 16(%rsp) 11 subq $(SS+8-\skip), %rsp
12 movq %rsi, 24(%rsp) 12 movq %rax, RAX(%rsp)
13 movq %rdi, 32(%rsp) 13 movq %rcx, RCX(%rsp)
14 movq %r8, 40(%rsp) 14 movq %rdx, RDX(%rsp)
15 movq %r9, 48(%rsp) 15 movq %rsi, RSI(%rsp)
16 movq %rdi, RDI(%rsp)
17 movq %r8, R8(%rsp)
18 movq %r9, R9(%rsp)
19 /* Move RIP to its proper location */
20 movq SS+8(%rsp), %rdx
21 movq %rdx, RIP(%rsp)
16 .endm 22 .endm
17 23
18 .macro MCOUNT_RESTORE_FRAME 24 .macro MCOUNT_RESTORE_FRAME skip=0
19 movq 48(%rsp), %r9 25 movq R9(%rsp), %r9
20 movq 40(%rsp), %r8 26 movq R8(%rsp), %r8
21 movq 32(%rsp), %rdi 27 movq RDI(%rsp), %rdi
22 movq 24(%rsp), %rsi 28 movq RSI(%rsp), %rsi
23 movq 16(%rsp), %rdx 29 movq RDX(%rsp), %rdx
24 movq 8(%rsp), %rcx 30 movq RCX(%rsp), %rcx
25 movq (%rsp), %rax 31 movq RAX(%rsp), %rax
26 addq $0x38, %rsp 32 addq $(SS+8-\skip), %rsp
27 .endm 33 .endm
28 34
29#endif 35#endif
@@ -34,6 +40,9 @@
34 40
35#ifdef CONFIG_DYNAMIC_FTRACE 41#ifdef CONFIG_DYNAMIC_FTRACE
36#define ARCH_SUPPORTS_FTRACE_OPS 1 42#define ARCH_SUPPORTS_FTRACE_OPS 1
43#ifdef CONFIG_X86_64
44#define ARCH_SUPPORTS_FTRACE_SAVE_REGS
45#endif
37#endif 46#endif
38 47
39#ifndef __ASSEMBLY__ 48#ifndef __ASSEMBLY__
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index e3e17a0b7ff8..5da11d1b85ae 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1109,7 +1109,8 @@ ENTRY(ftrace_caller)
1109 pushl %eax 1109 pushl %eax
1110 pushl %ecx 1110 pushl %ecx
1111 pushl %edx 1111 pushl %edx
1112 movl 0xc(%esp), %eax 1112 pushl $0 /* Pass NULL as regs pointer */
1113 movl 4*4(%esp), %eax
1113 movl 0x4(%ebp), %edx 1114 movl 0x4(%ebp), %edx
1114 leal function_trace_op, %ecx 1115 leal function_trace_op, %ecx
1115 subl $MCOUNT_INSN_SIZE, %eax 1116 subl $MCOUNT_INSN_SIZE, %eax
@@ -1118,6 +1119,7 @@ ENTRY(ftrace_caller)
1118ftrace_call: 1119ftrace_call:
1119 call ftrace_stub 1120 call ftrace_stub
1120 1121
1122 addl $4,%esp /* skip NULL pointer */
1121 popl %edx 1123 popl %edx
1122 popl %ecx 1124 popl %ecx
1123 popl %eax 1125 popl %eax
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 2b4f94c5dc60..52bda2e8f7aa 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -73,21 +73,34 @@ ENTRY(mcount)
73 retq 73 retq
74END(mcount) 74END(mcount)
75 75
76/* skip is set if stack has been adjusted */
77.macro ftrace_caller_setup skip=0
78 MCOUNT_SAVE_FRAME \skip
79
80 /* Load the ftrace_ops into the 3rd parameter */
81 leaq function_trace_op, %rdx
82
83 /* Load ip into the first parameter */
84 movq RIP(%rsp), %rdi
85 subq $MCOUNT_INSN_SIZE, %rdi
86 /* Load the parent_ip into the second parameter */
87 movq 8(%rbp), %rsi
88.endm
89
76ENTRY(ftrace_caller) 90ENTRY(ftrace_caller)
91 /* Check if tracing was disabled (quick check) */
77 cmpl $0, function_trace_stop 92 cmpl $0, function_trace_stop
78 jne ftrace_stub 93 jne ftrace_stub
79 94
80 MCOUNT_SAVE_FRAME 95 ftrace_caller_setup
81 96 /* regs go into 4th parameter (but make it NULL) */
82 leaq function_trace_op, %rdx 97 movq $0, %rcx
83 movq 0x38(%rsp), %rdi
84 movq 8(%rbp), %rsi
85 subq $MCOUNT_INSN_SIZE, %rdi
86 98
87GLOBAL(ftrace_call) 99GLOBAL(ftrace_call)
88 call ftrace_stub 100 call ftrace_stub
89 101
90 MCOUNT_RESTORE_FRAME 102 MCOUNT_RESTORE_FRAME
103ftrace_return:
91 104
92#ifdef CONFIG_FUNCTION_GRAPH_TRACER 105#ifdef CONFIG_FUNCTION_GRAPH_TRACER
93GLOBAL(ftrace_graph_call) 106GLOBAL(ftrace_graph_call)
@@ -98,6 +111,71 @@ GLOBAL(ftrace_stub)
98 retq 111 retq
99END(ftrace_caller) 112END(ftrace_caller)
100 113
114ENTRY(ftrace_regs_caller)
115 /* Save the current flags before compare (in SS location)*/
116 pushfq
117
118 /* Check if tracing was disabled (quick check) */
119 cmpl $0, function_trace_stop
120 jne ftrace_restore_flags
121
122 /* skip=8 to skip flags saved in SS */
123 ftrace_caller_setup 8
124
125 /* Save the rest of pt_regs */
126 movq %r15, R15(%rsp)
127 movq %r14, R14(%rsp)
128 movq %r13, R13(%rsp)
129 movq %r12, R12(%rsp)
130 movq %r11, R11(%rsp)
131 movq %r10, R10(%rsp)
132 movq %rbp, RBP(%rsp)
133 movq %rbx, RBX(%rsp)
134 /* Copy saved flags */
135 movq SS(%rsp), %rcx
136 movq %rcx, EFLAGS(%rsp)
137 /* Kernel segments */
138 movq $__KERNEL_DS, %rcx
139 movq %rcx, SS(%rsp)
140 movq $__KERNEL_CS, %rcx
141 movq %rcx, CS(%rsp)
142 /* Stack - skipping return address */
143 leaq SS+16(%rsp), %rcx
144 movq %rcx, RSP(%rsp)
145
146 /* regs go into 4th parameter */
147 leaq (%rsp), %rcx
148
149GLOBAL(ftrace_regs_call)
150 call ftrace_stub
151
152 /* Copy flags back to SS, to restore them */
153 movq EFLAGS(%rsp), %rax
154 movq %rax, SS(%rsp)
155
156 /* restore the rest of pt_regs */
157 movq R15(%rsp), %r15
158 movq R14(%rsp), %r14
159 movq R13(%rsp), %r13
160 movq R12(%rsp), %r12
161 movq R10(%rsp), %r10
162 movq RBP(%rsp), %rbp
163 movq RBX(%rsp), %rbx
164
165 /* skip=8 to skip flags saved in SS */
166 MCOUNT_RESTORE_FRAME 8
167
168 /* Restore flags */
169 popfq
170
171 jmp ftrace_return
172ftrace_restore_flags:
173 popfq
174 jmp ftrace_stub
175
176END(ftrace_regs_caller)
177
178
101#else /* ! CONFIG_DYNAMIC_FTRACE */ 179#else /* ! CONFIG_DYNAMIC_FTRACE */
102ENTRY(mcount) 180ENTRY(mcount)
103 cmpl $0, function_trace_stop 181 cmpl $0, function_trace_stop
@@ -120,7 +198,7 @@ GLOBAL(ftrace_stub)
120trace: 198trace:
121 MCOUNT_SAVE_FRAME 199 MCOUNT_SAVE_FRAME
122 200
123 movq 0x38(%rsp), %rdi 201 movq RIP(%rsp), %rdi
124 movq 8(%rbp), %rsi 202 movq 8(%rbp), %rsi
125 subq $MCOUNT_INSN_SIZE, %rdi 203 subq $MCOUNT_INSN_SIZE, %rdi
126 204
@@ -141,7 +219,7 @@ ENTRY(ftrace_graph_caller)
141 MCOUNT_SAVE_FRAME 219 MCOUNT_SAVE_FRAME
142 220
143 leaq 8(%rbp), %rdi 221 leaq 8(%rbp), %rdi
144 movq 0x38(%rsp), %rsi 222 movq RIP(%rsp), %rsi
145 movq (%rbp), %rdx 223 movq (%rbp), %rdx
146 subq $MCOUNT_INSN_SIZE, %rsi 224 subq $MCOUNT_INSN_SIZE, %rsi
147 225
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index c3a7cb4bf6e6..b90eb1a13071 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -206,6 +206,23 @@ static int
206ftrace_modify_code(unsigned long ip, unsigned const char *old_code, 206ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
207 unsigned const char *new_code); 207 unsigned const char *new_code);
208 208
209#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
210/*
211 * Should never be called:
212 * As it is only called by __ftrace_replace_code() which is called by
213 * ftrace_replace_code() that x86 overrides, and by ftrace_update_code()
214 * which is called to turn mcount into nops or nops into function calls
215 * but not to convert a function from not using regs to one that uses
216 * regs, which ftrace_modify_call() is for.
217 */
218int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
219 unsigned long addr)
220{
221 WARN_ON(1);
222 return -EINVAL;
223}
224#endif
225
209int ftrace_update_ftrace_func(ftrace_func_t func) 226int ftrace_update_ftrace_func(ftrace_func_t func)
210{ 227{
211 unsigned long ip = (unsigned long)(&ftrace_call); 228 unsigned long ip = (unsigned long)(&ftrace_call);
@@ -220,6 +237,16 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
220 237
221 ret = ftrace_modify_code(ip, old, new); 238 ret = ftrace_modify_code(ip, old, new);
222 239
240#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
241 /* Also update the regs callback function */
242 if (!ret) {
243 ip = (unsigned long)(&ftrace_regs_call);
244 memcpy(old, &ftrace_regs_call, MCOUNT_INSN_SIZE);
245 new = ftrace_call_replace(ip, (unsigned long)func);
246 ret = ftrace_modify_code(ip, old, new);
247 }
248#endif
249
223 atomic_dec(&modifying_ftrace_code); 250 atomic_dec(&modifying_ftrace_code);
224 251
225 return ret; 252 return ret;
@@ -299,6 +326,32 @@ static int add_brk_on_nop(struct dyn_ftrace *rec)
299 return add_break(rec->ip, old); 326 return add_break(rec->ip, old);
300} 327}
301 328
329/*
330 * If the record has the FTRACE_FL_REGS set, that means that it
331 * wants to convert to a callback that saves all regs. If FTRACE_FL_REGS
332 * is not not set, then it wants to convert to the normal callback.
333 */
334static unsigned long get_ftrace_addr(struct dyn_ftrace *rec)
335{
336 if (rec->flags & FTRACE_FL_REGS)
337 return (unsigned long)FTRACE_REGS_ADDR;
338 else
339 return (unsigned long)FTRACE_ADDR;
340}
341
342/*
343 * The FTRACE_FL_REGS_EN is set when the record already points to
344 * a function that saves all the regs. Basically the '_EN' version
345 * represents the current state of the function.
346 */
347static unsigned long get_ftrace_old_addr(struct dyn_ftrace *rec)
348{
349 if (rec->flags & FTRACE_FL_REGS_EN)
350 return (unsigned long)FTRACE_REGS_ADDR;
351 else
352 return (unsigned long)FTRACE_ADDR;
353}
354
302static int add_breakpoints(struct dyn_ftrace *rec, int enable) 355static int add_breakpoints(struct dyn_ftrace *rec, int enable)
303{ 356{
304 unsigned long ftrace_addr; 357 unsigned long ftrace_addr;
@@ -306,7 +359,7 @@ static int add_breakpoints(struct dyn_ftrace *rec, int enable)
306 359
307 ret = ftrace_test_record(rec, enable); 360 ret = ftrace_test_record(rec, enable);
308 361
309 ftrace_addr = (unsigned long)FTRACE_ADDR; 362 ftrace_addr = get_ftrace_addr(rec);
310 363
311 switch (ret) { 364 switch (ret) {
312 case FTRACE_UPDATE_IGNORE: 365 case FTRACE_UPDATE_IGNORE:
@@ -316,6 +369,10 @@ static int add_breakpoints(struct dyn_ftrace *rec, int enable)
316 /* converting nop to call */ 369 /* converting nop to call */
317 return add_brk_on_nop(rec); 370 return add_brk_on_nop(rec);
318 371
372 case FTRACE_UPDATE_MODIFY_CALL_REGS:
373 case FTRACE_UPDATE_MODIFY_CALL:
374 ftrace_addr = get_ftrace_old_addr(rec);
375 /* fall through */
319 case FTRACE_UPDATE_MAKE_NOP: 376 case FTRACE_UPDATE_MAKE_NOP:
320 /* converting a call to a nop */ 377 /* converting a call to a nop */
321 return add_brk_on_call(rec, ftrace_addr); 378 return add_brk_on_call(rec, ftrace_addr);
@@ -360,13 +417,21 @@ static int remove_breakpoint(struct dyn_ftrace *rec)
360 * If not, don't touch the breakpoint, we make just create 417 * If not, don't touch the breakpoint, we make just create
361 * a disaster. 418 * a disaster.
362 */ 419 */
363 ftrace_addr = (unsigned long)FTRACE_ADDR; 420 ftrace_addr = get_ftrace_addr(rec);
421 nop = ftrace_call_replace(ip, ftrace_addr);
422
423 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) == 0)
424 goto update;
425
426 /* Check both ftrace_addr and ftrace_old_addr */
427 ftrace_addr = get_ftrace_old_addr(rec);
364 nop = ftrace_call_replace(ip, ftrace_addr); 428 nop = ftrace_call_replace(ip, ftrace_addr);
365 429
366 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) 430 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
367 return -EINVAL; 431 return -EINVAL;
368 } 432 }
369 433
434 update:
370 return probe_kernel_write((void *)ip, &nop[0], 1); 435 return probe_kernel_write((void *)ip, &nop[0], 1);
371} 436}
372 437
@@ -405,12 +470,14 @@ static int add_update(struct dyn_ftrace *rec, int enable)
405 470
406 ret = ftrace_test_record(rec, enable); 471 ret = ftrace_test_record(rec, enable);
407 472
408 ftrace_addr = (unsigned long)FTRACE_ADDR; 473 ftrace_addr = get_ftrace_addr(rec);
409 474
410 switch (ret) { 475 switch (ret) {
411 case FTRACE_UPDATE_IGNORE: 476 case FTRACE_UPDATE_IGNORE:
412 return 0; 477 return 0;
413 478
479 case FTRACE_UPDATE_MODIFY_CALL_REGS:
480 case FTRACE_UPDATE_MODIFY_CALL:
414 case FTRACE_UPDATE_MAKE_CALL: 481 case FTRACE_UPDATE_MAKE_CALL:
415 /* converting nop to call */ 482 /* converting nop to call */
416 return add_update_call(rec, ftrace_addr); 483 return add_update_call(rec, ftrace_addr);
@@ -455,12 +522,14 @@ static int finish_update(struct dyn_ftrace *rec, int enable)
455 522
456 ret = ftrace_update_record(rec, enable); 523 ret = ftrace_update_record(rec, enable);
457 524
458 ftrace_addr = (unsigned long)FTRACE_ADDR; 525 ftrace_addr = get_ftrace_addr(rec);
459 526
460 switch (ret) { 527 switch (ret) {
461 case FTRACE_UPDATE_IGNORE: 528 case FTRACE_UPDATE_IGNORE:
462 return 0; 529 return 0;
463 530
531 case FTRACE_UPDATE_MODIFY_CALL_REGS:
532 case FTRACE_UPDATE_MODIFY_CALL:
464 case FTRACE_UPDATE_MAKE_CALL: 533 case FTRACE_UPDATE_MAKE_CALL:
465 /* converting nop to call */ 534 /* converting nop to call */
466 return finish_update_call(rec, ftrace_addr); 535 return finish_update_call(rec, ftrace_addr);
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index e4202881fb00..ab39990cc43f 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -71,12 +71,28 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
71 * could be controled by following calls: 71 * could be controled by following calls:
72 * ftrace_function_local_enable 72 * ftrace_function_local_enable
73 * ftrace_function_local_disable 73 * ftrace_function_local_disable
74 * SAVE_REGS - The ftrace_ops wants regs saved at each function called
75 * and passed to the callback. If this flag is set, but the
76 * architecture does not support passing regs
77 * (ARCH_SUPPORTS_FTRACE_SAVE_REGS is not defined), then the
78 * ftrace_ops will fail to register, unless the next flag
79 * is set.
80 * SAVE_REGS_IF_SUPPORTED - This is the same as SAVE_REGS, but if the
81 * handler can handle an arch that does not save regs
82 * (the handler tests if regs == NULL), then it can set
83 * this flag instead. It will not fail registering the ftrace_ops
84 * but, the regs field will be NULL if the arch does not support
85 * passing regs to the handler.
86 * Note, if this flag is set, the SAVE_REGS flag will automatically
87 * get set upon registering the ftrace_ops, if the arch supports it.
74 */ 88 */
75enum { 89enum {
76 FTRACE_OPS_FL_ENABLED = 1 << 0, 90 FTRACE_OPS_FL_ENABLED = 1 << 0,
77 FTRACE_OPS_FL_GLOBAL = 1 << 1, 91 FTRACE_OPS_FL_GLOBAL = 1 << 1,
78 FTRACE_OPS_FL_DYNAMIC = 1 << 2, 92 FTRACE_OPS_FL_DYNAMIC = 1 << 2,
79 FTRACE_OPS_FL_CONTROL = 1 << 3, 93 FTRACE_OPS_FL_CONTROL = 1 << 3,
94 FTRACE_OPS_FL_SAVE_REGS = 1 << 4,
95 FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 1 << 5,
80}; 96};
81 97
82struct ftrace_ops { 98struct ftrace_ops {
@@ -254,12 +270,31 @@ extern void unregister_ftrace_function_probe_all(char *glob);
254 270
255extern int ftrace_text_reserved(void *start, void *end); 271extern int ftrace_text_reserved(void *start, void *end);
256 272
273/*
274 * The dyn_ftrace record's flags field is split into two parts.
275 * the first part which is '0-FTRACE_REF_MAX' is a counter of
276 * the number of callbacks that have registered the function that
277 * the dyn_ftrace descriptor represents.
278 *
279 * The second part is a mask:
280 * ENABLED - the function is being traced
281 * REGS - the record wants the function to save regs
282 * REGS_EN - the function is set up to save regs.
283 *
284 * When a new ftrace_ops is registered and wants a function to save
285 * pt_regs, the rec->flag REGS is set. When the function has been
286 * set up to save regs, the REG_EN flag is set. Once a function
287 * starts saving regs it will do so until all ftrace_ops are removed
288 * from tracing that function.
289 */
257enum { 290enum {
258 FTRACE_FL_ENABLED = (1 << 30), 291 FTRACE_FL_ENABLED = (1UL << 29),
292 FTRACE_FL_REGS = (1UL << 30),
293 FTRACE_FL_REGS_EN = (1UL << 31)
259}; 294};
260 295
261#define FTRACE_FL_MASK (0x3UL << 30) 296#define FTRACE_FL_MASK (0x7UL << 29)
262#define FTRACE_REF_MAX ((1 << 30) - 1) 297#define FTRACE_REF_MAX ((1UL << 29) - 1)
263 298
264struct dyn_ftrace { 299struct dyn_ftrace {
265 union { 300 union {
@@ -290,9 +325,23 @@ enum {
290 FTRACE_STOP_FUNC_RET = (1 << 4), 325 FTRACE_STOP_FUNC_RET = (1 << 4),
291}; 326};
292 327
328/*
329 * The FTRACE_UPDATE_* enum is used to pass information back
330 * from the ftrace_update_record() and ftrace_test_record()
331 * functions. These are called by the code update routines
332 * to find out what is to be done for a given function.
333 *
334 * IGNORE - The function is already what we want it to be
335 * MAKE_CALL - Start tracing the function
336 * MODIFY_CALL - Stop saving regs for the function
337 * MODIFY_CALL_REGS - Start saving regs for the function
338 * MAKE_NOP - Stop tracing the function
339 */
293enum { 340enum {
294 FTRACE_UPDATE_IGNORE, 341 FTRACE_UPDATE_IGNORE,
295 FTRACE_UPDATE_MAKE_CALL, 342 FTRACE_UPDATE_MAKE_CALL,
343 FTRACE_UPDATE_MODIFY_CALL,
344 FTRACE_UPDATE_MODIFY_CALL_REGS,
296 FTRACE_UPDATE_MAKE_NOP, 345 FTRACE_UPDATE_MAKE_NOP,
297}; 346};
298 347
@@ -344,7 +393,9 @@ extern int ftrace_dyn_arch_init(void *data);
344extern void ftrace_replace_code(int enable); 393extern void ftrace_replace_code(int enable);
345extern int ftrace_update_ftrace_func(ftrace_func_t func); 394extern int ftrace_update_ftrace_func(ftrace_func_t func);
346extern void ftrace_caller(void); 395extern void ftrace_caller(void);
396extern void ftrace_regs_caller(void);
347extern void ftrace_call(void); 397extern void ftrace_call(void);
398extern void ftrace_regs_call(void);
348extern void mcount_call(void); 399extern void mcount_call(void);
349 400
350void ftrace_modify_all_code(int command); 401void ftrace_modify_all_code(int command);
@@ -352,6 +403,15 @@ void ftrace_modify_all_code(int command);
352#ifndef FTRACE_ADDR 403#ifndef FTRACE_ADDR
353#define FTRACE_ADDR ((unsigned long)ftrace_caller) 404#define FTRACE_ADDR ((unsigned long)ftrace_caller)
354#endif 405#endif
406
407#ifndef FTRACE_REGS_ADDR
408#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
409# define FTRACE_REGS_ADDR ((unsigned long)ftrace_regs_caller)
410#else
411# define FTRACE_REGS_ADDR FTRACE_ADDR
412#endif
413#endif
414
355#ifdef CONFIG_FUNCTION_GRAPH_TRACER 415#ifdef CONFIG_FUNCTION_GRAPH_TRACER
356extern void ftrace_graph_caller(void); 416extern void ftrace_graph_caller(void);
357extern int ftrace_enable_ftrace_graph_caller(void); 417extern int ftrace_enable_ftrace_graph_caller(void);
@@ -407,6 +467,39 @@ extern int ftrace_make_nop(struct module *mod,
407 */ 467 */
408extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr); 468extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
409 469
470#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
471/**
472 * ftrace_modify_call - convert from one addr to another (no nop)
473 * @rec: the mcount call site record
474 * @old_addr: the address expected to be currently called to
475 * @addr: the address to change to
476 *
477 * This is a very sensitive operation and great care needs
478 * to be taken by the arch. The operation should carefully
479 * read the location, check to see if what is read is indeed
480 * what we expect it to be, and then on success of the compare,
481 * it should write to the location.
482 *
483 * The code segment at @rec->ip should be a caller to @old_addr
484 *
485 * Return must be:
486 * 0 on success
487 * -EFAULT on error reading the location
488 * -EINVAL on a failed compare of the contents
489 * -EPERM on error writing to the location
490 * Any other value will be considered a failure.
491 */
492extern int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
493 unsigned long addr);
494#else
495/* Should never be called */
496static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
497 unsigned long addr)
498{
499 return -EINVAL;
500}
501#endif
502
410/* May be defined in arch */ 503/* May be defined in arch */
411extern int ftrace_arch_read_dyn_info(char *buf, int size); 504extern int ftrace_arch_read_dyn_info(char *buf, int size);
412 505
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6ff07ad0ede3..c55f7e274613 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -314,6 +314,20 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
314 if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK) 314 if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK)
315 return -EINVAL; 315 return -EINVAL;
316 316
317#ifndef ARCH_SUPPORTS_FTRACE_SAVE_REGS
318 /*
319 * If the ftrace_ops specifies SAVE_REGS, then it only can be used
320 * if the arch supports it, or SAVE_REGS_IF_SUPPORTED is also set.
321 * Setting SAVE_REGS_IF_SUPPORTED makes SAVE_REGS irrelevant.
322 */
323 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS &&
324 !(ops->flags & FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED))
325 return -EINVAL;
326
327 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED)
328 ops->flags |= FTRACE_OPS_FL_SAVE_REGS;
329#endif
330
317 if (!core_kernel_data((unsigned long)ops)) 331 if (!core_kernel_data((unsigned long)ops))
318 ops->flags |= FTRACE_OPS_FL_DYNAMIC; 332 ops->flags |= FTRACE_OPS_FL_DYNAMIC;
319 333
@@ -1515,6 +1529,12 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
1515 rec->flags++; 1529 rec->flags++;
1516 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX)) 1530 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX))
1517 return; 1531 return;
1532 /*
1533 * If any ops wants regs saved for this function
1534 * then all ops will get saved regs.
1535 */
1536 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
1537 rec->flags |= FTRACE_FL_REGS;
1518 } else { 1538 } else {
1519 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0)) 1539 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0))
1520 return; 1540 return;
@@ -1606,18 +1626,59 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
1606 if (enable && (rec->flags & ~FTRACE_FL_MASK)) 1626 if (enable && (rec->flags & ~FTRACE_FL_MASK))
1607 flag = FTRACE_FL_ENABLED; 1627 flag = FTRACE_FL_ENABLED;
1608 1628
1629 /*
1630 * If enabling and the REGS flag does not match the REGS_EN, then
1631 * do not ignore this record. Set flags to fail the compare against
1632 * ENABLED.
1633 */
1634 if (flag &&
1635 (!(rec->flags & FTRACE_FL_REGS) != !(rec->flags & FTRACE_FL_REGS_EN)))
1636 flag |= FTRACE_FL_REGS;
1637
1609 /* If the state of this record hasn't changed, then do nothing */ 1638 /* If the state of this record hasn't changed, then do nothing */
1610 if ((rec->flags & FTRACE_FL_ENABLED) == flag) 1639 if ((rec->flags & FTRACE_FL_ENABLED) == flag)
1611 return FTRACE_UPDATE_IGNORE; 1640 return FTRACE_UPDATE_IGNORE;
1612 1641
1613 if (flag) { 1642 if (flag) {
1614 if (update) 1643 /* Save off if rec is being enabled (for return value) */
1644 flag ^= rec->flags & FTRACE_FL_ENABLED;
1645
1646 if (update) {
1615 rec->flags |= FTRACE_FL_ENABLED; 1647 rec->flags |= FTRACE_FL_ENABLED;
1616 return FTRACE_UPDATE_MAKE_CALL; 1648 if (flag & FTRACE_FL_REGS) {
1649 if (rec->flags & FTRACE_FL_REGS)
1650 rec->flags |= FTRACE_FL_REGS_EN;
1651 else
1652 rec->flags &= ~FTRACE_FL_REGS_EN;
1653 }
1654 }
1655
1656 /*
1657 * If this record is being updated from a nop, then
1658 * return UPDATE_MAKE_CALL.
1659 * Otherwise, if the EN flag is set, then return
1660 * UPDATE_MODIFY_CALL_REGS to tell the caller to convert
1661 * from the non-save regs, to a save regs function.
1662 * Otherwise,
1663 * return UPDATE_MODIFY_CALL to tell the caller to convert
1664 * from the save regs, to a non-save regs function.
1665 */
1666 if (flag & FTRACE_FL_ENABLED)
1667 return FTRACE_UPDATE_MAKE_CALL;
1668 else if (rec->flags & FTRACE_FL_REGS_EN)
1669 return FTRACE_UPDATE_MODIFY_CALL_REGS;
1670 else
1671 return FTRACE_UPDATE_MODIFY_CALL;
1617 } 1672 }
1618 1673
1619 if (update) 1674 if (update) {
1620 rec->flags &= ~FTRACE_FL_ENABLED; 1675 /* If there's no more users, clear all flags */
1676 if (!(rec->flags & ~FTRACE_FL_MASK))
1677 rec->flags = 0;
1678 else
1679 /* Just disable the record (keep REGS state) */
1680 rec->flags &= ~FTRACE_FL_ENABLED;
1681 }
1621 1682
1622 return FTRACE_UPDATE_MAKE_NOP; 1683 return FTRACE_UPDATE_MAKE_NOP;
1623} 1684}
@@ -1652,13 +1713,17 @@ int ftrace_test_record(struct dyn_ftrace *rec, int enable)
1652static int 1713static int
1653__ftrace_replace_code(struct dyn_ftrace *rec, int enable) 1714__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
1654{ 1715{
1716 unsigned long ftrace_old_addr;
1655 unsigned long ftrace_addr; 1717 unsigned long ftrace_addr;
1656 int ret; 1718 int ret;
1657 1719
1658 ftrace_addr = (unsigned long)FTRACE_ADDR;
1659
1660 ret = ftrace_update_record(rec, enable); 1720 ret = ftrace_update_record(rec, enable);
1661 1721
1722 if (rec->flags & FTRACE_FL_REGS)
1723 ftrace_addr = (unsigned long)FTRACE_REGS_ADDR;
1724 else
1725 ftrace_addr = (unsigned long)FTRACE_ADDR;
1726
1662 switch (ret) { 1727 switch (ret) {
1663 case FTRACE_UPDATE_IGNORE: 1728 case FTRACE_UPDATE_IGNORE:
1664 return 0; 1729 return 0;
@@ -1668,6 +1733,15 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
1668 1733
1669 case FTRACE_UPDATE_MAKE_NOP: 1734 case FTRACE_UPDATE_MAKE_NOP:
1670 return ftrace_make_nop(NULL, rec, ftrace_addr); 1735 return ftrace_make_nop(NULL, rec, ftrace_addr);
1736
1737 case FTRACE_UPDATE_MODIFY_CALL_REGS:
1738 case FTRACE_UPDATE_MODIFY_CALL:
1739 if (rec->flags & FTRACE_FL_REGS)
1740 ftrace_old_addr = (unsigned long)FTRACE_ADDR;
1741 else
1742 ftrace_old_addr = (unsigned long)FTRACE_REGS_ADDR;
1743
1744 return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr);
1671 } 1745 }
1672 1746
1673 return -1; /* unknow ftrace bug */ 1747 return -1; /* unknow ftrace bug */
@@ -2421,8 +2495,9 @@ static int t_show(struct seq_file *m, void *v)
2421 2495
2422 seq_printf(m, "%ps", (void *)rec->ip); 2496 seq_printf(m, "%ps", (void *)rec->ip);
2423 if (iter->flags & FTRACE_ITER_ENABLED) 2497 if (iter->flags & FTRACE_ITER_ENABLED)
2424 seq_printf(m, " (%ld)", 2498 seq_printf(m, " (%ld)%s",
2425 rec->flags & ~FTRACE_FL_MASK); 2499 rec->flags & ~FTRACE_FL_MASK,
2500 rec->flags & FTRACE_FL_REGS ? " R" : "");
2426 seq_printf(m, "\n"); 2501 seq_printf(m, "\n");
2427 2502
2428 return 0; 2503 return 0;