ftrace/kprobes: Setting up ftrace for kprobes
Subsystems (4)
Steven Rostedt
maintainerv4 cover ftrace/kprobes: Setting up ftrace for kprobes
I'm only posting patches that changed from v3. Those changes include:
Saving the flags after MCOUNT_RESTORE_FRAME (suggested by Masami) I decided to restore flags from the pt_regs, such that a kprobe could change the flags register.
I added the offset fix for function parent pointer (pointed out by
Alexander van Heukelum).
I fixed the i386 version of "save regs" to restore flags correctly (as pointed out by Masami Hiramatsu).
I also added two new patches.
1) I removed the double check to function_trace_stop variable that the function graph tracer was doing (it tested it in the function tracer trampoline, and again in the function graph trampoline).
2) I added internal recursion protection, that I found kprobes was triggering. This was long overdue anyway.
Masami,
Could you give your reviewed by tags for the first two patches, at least.
Thanks,
-- Steve
Steven Rostedt (4):
ftrace/x86: Add separate function to save regs ftrace/x86: Add save_regs for i386 function calls ftrace/x86: Remove function_trace_stop check from graph caller ftrace/x86_64: Add recursion protection inside mcount caller
----
arch/x86/include/asm/ftrace.h | 47 +++++++++------- arch/x86/kernel/entry_32.S | 93 ++++++++++++++++++++++++++++-- arch/x86/kernel/entry_64.S | 125 ++++++++++++++++++++++++++++++++++++----- arch/x86/kernel/ftrace.c | 80 ++++++++++++++++++++++++-- include/linux/ftrace.h | 109 ++++++++++++++++++++++++++++++++--- kernel/trace/ftrace.c | 91 +++++++++++++++++++++++++++--- 6 files changed, 485 insertions(+), 60 deletions(-)
Steven Rostedt
maintainerRFC PATCH v4 1/4 ftrace/x86: Add separate function to save regs
From: Steven Rostedt <[email protected]>
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.
--- arch/x86/include/asm/ftrace.h | 47 ++++++++++-------- arch/x86/kernel/entry_32.S | 4 +- arch/x86/kernel/entry_64.S | 94 +++++++++++++++++++++++++++++++++--- arch/x86/kernel/ftrace.c | 77 +++++++++++++++++++++++++++-- include/linux/ftrace.h | 107 ++++++++++++++++++++++++++++++++++++++--- kernel/trace/ftrace.c | 91 ++++++++++++++++++++++++++++++++--- 6 files changed, 373 insertions(+), 47 deletions(-)
arch/x86/include/asm/ftrace.h +28 -19
@@ -3,27 +3,33 @@#ifdef __ASSEMBLY__ - .macro MCOUNT_SAVE_FRAME - /* taken from glibc */ - subq $0x38, %rsp - movq %rax, (%rsp) - movq %rcx, 8(%rsp) - movq %rdx, 16(%rsp) - movq %rsi, 24(%rsp) - movq %rdi, 32(%rsp) - movq %r8, 40(%rsp) - movq %r9, 48(%rsp) +/* skip is set if the stack was already partially adjusted */ + .macro MCOUNT_SAVE_FRAME skip=0 +/* +* We add enough stack to save all regs. + */ + subq $(SS+8-\skip), %rsp + movq %rax, RAX(%rsp) + movq %rcx, RCX(%rsp) + movq %rdx, RDX(%rsp) + movq %rsi, RSI(%rsp) + movq %rdi, RDI(%rsp) + movq %r8, R8(%rsp) + movq %r9, R9(%rsp) + /* Move RIP to its proper location */ + movq SS+8(%rsp), %rdx + movq %rdx, RIP(%rsp) .endm - .macro MCOUNT_RESTORE_FRAME - movq 48(%rsp), %r9 - movq 40(%rsp), %r8 - movq 32(%rsp), %rdi - movq 24(%rsp), %rsi - movq 16(%rsp), %rdx - movq 8(%rsp), %rcx - movq (%rsp), %rax - addq $0x38, %rsp + .macro MCOUNT_RESTORE_FRAME skip=0 + movq R9(%rsp), %r9 + movq R8(%rsp), %r8 + movq RDI(%rsp), %rdi + movq RSI(%rsp), %rsi + movq RDX(%rsp), %rdx + movq RCX(%rsp), %rcx + movq RAX(%rsp), %rax + addq $(SS+8-\skip), %rsp .endm #endif
@@ -34,6 +40,9 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 +#ifdef CONFIG_X86_64 +#define ARCH_SUPPORTS_FTRACE_SAVE_REGS +#endif #endif #ifndef __ASSEMBLY__
arch/x86/kernel/entry_32.S +3 -1
@@ -1109,7 +1109,8 @@ ENTRY(ftrace_caller) pushl %eax pushl %ecx pushl %edx - movl 0xc(%esp), %eax + pushl $0 /* Pass NULL as regs pointer */ + movl 4*4(%esp), %eax movl 0x4(%ebp), %edx leal function_trace_op, %ecx subl $MCOUNT_INSN_SIZE, %eax
@@ -1118,6 +1119,7 @@ ENTRY(ftrace_caller) ftrace_call: call ftrace_stub + addl $4,%esp /* skip NULL pointer */ popl %edx popl %ecx popl %eax
arch/x86/kernel/entry_64.S +86 -8
127 lines not on this page · raw message
arch/x86/kernel/ftrace.c +73 -4
141 lines not on this page · raw message
include/linux/ftrace.h +100 -7
152 lines not on this page · raw message
kernel/trace/ftrace.c +83 -8
140 lines not on this page · raw message
Signature · 1 line
1.7.10
Re: [RFC][PATCH 1/4 v4] ftrace/x86: Add separate function to save regs
Quoted 18 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Add a way to have different functions calling different trampolines. If a
ftrace_opswants 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_opsregistered 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_64implements the full regs saving, and i386 just passes a NULL for regs to satisfy theftrace_opspassing. Where an arch must supply both regs andftrace_opsparameters, even if regs is just NULL.
Quoted 9 lines
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_REGSwhen registering theftrace_ops. If the arch does not support saving regs then theftrace_opswill fail to register. The flagFTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTEDmay be set that will prevent theftrace_opsfrom failing to register. In this case, the handler may either check if regs is not NULL or check ifARCH_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.
OK, this is good for me:)
Thank you!
Quoted 4 lines
Cc Alexander van Heukelum <[email protected]>Signed-off-by Steven Rostedt <[email protected]>---
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: [email protected]
Steven Rostedt
maintainerRFC PATCH v4 2/4 ftrace/x86: Add save_regs for i386 function calls
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
Add saving full regs for function tracing on i386. The saving of regs was influenced by patches sent out by Masami Hiramatsu.
--- arch/x86/include/asm/ftrace.h | 2 -- arch/x86/kernel/entry_32.S | 58 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/ftrace.c | 4 --- 3 files changed, 58 insertions(+), 6 deletions(-)
arch/x86/include/asm/ftrace.h +0 -2
@@ -40,10 +40,8 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 -#ifdef CONFIG_X86_64 #define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif -#endif #ifndef __ASSEMBLY__extern void mcount (void );
arch/x86/kernel/entry_32.S +58 -0
70 lines not on this page · raw message
arch/x86/kernel/ftrace.c +0 -4
@@ -206,7 +206,6 @@ static int ftrace_modify_code(unsigned long ip, unsigned const char *old_code, unsigned const char *new_code); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* * Should never be called: * As it is only called by __ftrace_replace_code() which is called by
@@ -221,7 +220,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,WARN_ON (1 );return -EINVAL ; } -#endif int ftrace_update_ftrace_func (ftrace_func_t func) {
@@ -237,7 +235,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ret =ftrace_modify_code (ip, old, new); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* Also update the regs callback function */ if (!ret) { ip = (unsigned long )(&ftrace_regs_call);
@@ -245,7 +242,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) new =ftrace_call_replace (ip, (unsigned long )func); ret =ftrace_modify_code (ip, old, new); } -#endif atomic_dec (&modifying_ftrace_code);
Signature · 1 line
1.7.10
Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 48 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Add saving full regs for function tracing on i386. The saving of regs was influenced by patches sent out by Masami Hiramatsu.
Cc Masami Hiramatsu <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- arch/x86/include/asm/ftrace.h | 2 -- arch/x86/kernel/entry_32.S | 58 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/ftrace.c | 4 --- 3 files changed, 58 insertions(+), 6 deletions(-)arch/x86/include/asm/ftrace.h +0
-2@@ -40,10 +40,8 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 -#ifdef CONFIG_X86_64 #define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif -#endif #ifndef __ASSEMBLY__extern void mcount (void );arch/x86/kernel/entry_32.S +4
-0@@ -1123,6 +1123,7 @@ ftrace_call: popl %edx popl %ecx popl %eax +ftrace_ret: #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl ftrace_graph_call ftrace_graph_call:@@ -1134,6 +1135,63 @@ ftrace_stub: ret END(ftrace_caller) +ENTRY(ftrace_regs_caller) + pushf /* push flags before compare (in ss location) */ + cmpl $0, function_trace_stop
arch/x86/kernel/entry_32.S ftrace_stub: · line 1150
Quoted 10 lines
arch/x86/kernel/entry_32.S +10
-0+ jne ftrace_restore_flags + + pushl %esp /* Save stack in sp location */ + subl $4, (%esp) /* Adjust saved stack to skip saved flags */ + pushl 4(%esp) /* Save flags in correct position */ + movl $__KERNEL_DS, 8(%esp) /* Save ss */ + pushl $__KERNEL_CS + pushl 4*4(%esp) /* Save the ip */ + subl $MCOUNT_INSN_SIZE, (%esp) /* Adjust ip */ + pushl $0 /* Load 0 into orig_ax */
Oops, you might forget that the i386's interrupt stack layout is a bit different from x86-64.
On x86-64, regs->sp directly points the top of stack.
On the other hand (i386), regs->sp IS the top of stack. You can see below code in arch/x86/include/asm/ptrace.h
---
/*
* X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode
* when it traps. The previous stack will be directly underneath the saved
* registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. *
* This is valid only for kernel mode traps.
*/
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) {
#ifdef CONFIG_X86_32
return (unsigned long)(®s->sp);
#else
return regs->sp;#endif
}
---
This means that you need a trick here.
sp-> [retaddr] (*)-> [orig_stack]
Here is the stack layout when the ftrace_regs_caller is called. (*) points the original stack pointer. this means that regs->sp has placed at (*). After doing pushf, it changed as below.
(what user expects) sp-> [flags] <- regs.cs [retaddr] <- regs.flags (*)-> [orig_stack] <- regs.sp
So we have to change this stack layout as the user expected. That is what I did it in my previous series;
https://lkml.org/lkml/2012/6/5/119
In this patch, I clobbered the return address on the stack and stores it in the local stack because of that reason.
+ movl 14*4(%esp), %eax /* Load return address */
+ pushl %eax /* Save return address (+4) */
+ subl $MCOUNT_INSN_SIZE, %eax
+ movl %eax, 12*4+4(%esp) /* Store IP */
+ movl 13*4+4(%esp), %edx /* Load flags */
+ movl %edx, 14*4+4(%esp) /* Store flags */
+ movl $__KERNEL_CS, %edx
+ movl %edx, 13*4+4(%esp)
Thank you,
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: [email protected]
Steven Rostedt
maintainerRe: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
I'm slowly getting this patch set into working order ;-)
Quoted 31 lines · Masami Hiramatsu
Quoted 4 lines
arch/x86/kernel/entry_32.S +3
-0+ENTRY(ftrace_regs_caller) + pushf /* push flags before compare (in ss location) */ + cmpl $0, function_trace_stoparch/x86/kernel/entry_32.S ftrace_stub: · line 1150
Quoted 10 lines
arch/x86/kernel/entry_32.S +10
-0+ jne ftrace_restore_flags + + pushl %esp /* Save stack in sp location */ + subl $4, (%esp) /* Adjust saved stack to skip saved flags */ + pushl 4(%esp) /* Save flags in correct position */ + movl $__KERNEL_DS, 8(%esp) /* Save ss */ + pushl $__KERNEL_CS + pushl 4*4(%esp) /* Save the ip */ + subl $MCOUNT_INSN_SIZE, (%esp) /* Adjust ip */ + pushl $0 /* Load 0 into orig_ax */Oops, you might forget that the i386's interrupt stack layout is a bit different from x86-64.
On x86-64,
regs->spdirectly points the top of stack.
On the other hand (i386),regs->spIS the top of stack. You can see below code inarch/x86/include/asm/ptrace.h
---
/*
*X86_32CPUs don't save ss and esp if the CPU is already in kernel mode
* when it traps. The previous stack will be directly underneath the saved
* registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. *
* This is valid only for kernel mode traps.
*/
static inline unsigned longkernel_stack_pointer(struct pt_regs *regs){
Quoted 5 lines
#ifdef CONFIG_X86_32 return (unsigned long)(®s->sp); #else return regs->sp;#endif
Yuck yuck yuck!
Quoted 12 lines
}
---This means that you need a trick here.
sp-> [retaddr] (*)-> [orig_stack]Here is the stack layout when the
ftrace_regs_calleris called. (*) points the original stack pointer. this means thatregs->sphas placed at (*). After doing pushf, it changed as below.
Quoted 7 lines
(what user expects) sp-> [flags] <- regs.cs [retaddr] <- regs.flags (*)-> [orig_stack] <- regs.spSo we have to change this stack layout as the user expected. That is what I did it in my previous series;
Yeah, I saw that you did this, but didn't fully understand why. I completely forgot about that hack in x86_32 :-(
This is why I'm insisting to get your Reviewed-by, as you seem to be more up-to-date on the subtleties between 32 and 64 than I am.
Quoted 6 lines
https://lkml.org/lkml/2012/6/5/119
In this patch, I clobbered the return address on the stack and stores it in the local stack because of that reason.
Review
Quoted 8 lines
(quoted diff) +8
-0+ movl 14*4(%esp), %eax /* Load return address */ + pushl %eax /* Save return address (+4) */ + subl $MCOUNT_INSN_SIZE, %eax + movl %eax, 12*4+4(%esp) /* Store IP */ + movl 13*4+4(%esp), %edx /* Load flags */ + movl %edx, 14*4+4(%esp) /* Store flags */ + movl $__KERNEL_CS, %edx + movl %edx, 13*4+4(%esp)
Well the change log does say that my patch set was influenced by your code. I started to veer from that. I shouldn't have.
Quoted 3 lines
Thank you,
No, thank you!
/me goes to work on v5.
-- Steve
Steven Rostedt
maintainerRe: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
In reply to Masami HiramatsuQuoted 9 lines · Masami Hiramatsu
/*
*X86_32CPUs don't save ss and esp if the CPU is already in kernel mode
* when it traps. The previous stack will be directly underneath the saved
* registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. *
* This is valid only for kernel mode traps.
*/
static inline unsigned longkernel_stack_pointer(struct pt_regs *regs){
Quoted 6 lines
#ifdef CONFIG_X86_32 return (unsigned long)(®s->sp); #else return regs->sp;#endif
}
I found that regs_get_register() doesn't honor this either. Thus, kprobes in tracing gets this:
# echo 'p:ftrace sys_read+4 s=%sp' > /debug/tracing/kprobe_events
# echo 1 > /debug/tracing/events/kprobes/enable
# cat trace
sshd-1345 [000] d... 489.117168: ftrace: (sys_read+0x4/0x70) s=b7e96768
sshd-1345 [000] d... 489.117191: ftrace: (sys_read+0x4/0x70) s=b7e96768
cat-1447 [000] d... 489.117392: ftrace: (sys_read+0x4/0x70) s=5a7
cat-1447 [001] d... 489.118023: ftrace: (sys_read+0x4/0x70) s=b77ad05f
less-1448 [000] d... 489.118079: ftrace: (sys_read+0x4/0x70) s=b7762e06
less-1448 [000] d... 489.118117: ftrace: (sys_read+0x4/0x70) s=b7764970Note, I added +4 (which is still a normal kprobe, and not a ftrace one) because it updates the stack where regs->sp would definitely not be a kernel stack.
This patch fixes it:
arch/x86/include/asm/ptrace.h +5 -0
@@ -246,6 +246,11 @@ static inline unsigned long regs_get_register(struct pt_regs *regs, {if (unlikely (offset >MAX_REG_OFFSET ))return 0 ; +#ifdef CONFIG_X86_32 +if (offset == offsetof(struct pt_regs , sp) && + regs->cs == __KERNEL_CS) +return kernel_stack_pointer (regs); +#endif return *(unsigned long *)((unsigned long )regs + offset); }
sshd-1352 [000] d... 362.348016: ftrace: (sys_read+0x4/0x70) s=f3febfa8
sshd-1352 [000] d... 362.348048: ftrace: (sys_read+0x4/0x70) s=f3febfa8
bash-1355 [001] d... 362.348081: ftrace: (sys_read+0x4/0x70) s=f5075fa8
sshd-1352 [000] d... 362.348082: ftrace: (sys_read+0x4/0x70) s=f3febfa8
sshd-1352 [000] d... 362.690950: ftrace: (sys_read+0x4/0x70) s=f3febfa8
bash-1355 [001] d... 362.691033: ftrace: (sys_read+0x4/0x70) s=f5075fa8I'll post that patch separately.
Quoted 24 lines
---
This means that you need a trick here.
sp-> [retaddr] (*)-> [orig_stack]Here is the stack layout when the
ftrace_regs_calleris called. (*) points the original stack pointer. this means thatregs->sphas placed at (*). After doing pushf, it changed as below.(what user expects) sp-> [flags] <- regs.cs [retaddr] <- regs.flags (*)-> [orig_stack] <- regs.spSo we have to change this stack layout as the user expected. That is what I did it in my previous series;
https://lkml.org/lkml/2012/6/5/119
In this patch, I clobbered the return address on the stack and stores it in the local stack because of that reason.
Review
Quoted 8 lines
(quoted diff) +8
-0+ movl 14*4(%esp), %eax /* Load return address */ + pushl %eax /* Save return address (+4) */ + subl $MCOUNT_INSN_SIZE, %eax + movl %eax, 12*4+4(%esp) /* Store IP */ + movl 13*4+4(%esp), %edx /* Load flags */ + movl %edx, 14*4+4(%esp) /* Store flags */ + movl $__KERNEL_CS, %edx + movl %edx, 13*4+4(%esp)
I did something slightly different but basically the same. Here's the new version:
-- Steve
From: Steven Rostedt <[email protected]>
Date: Tue, 5 Jun 2012 20:00:11 -0400
Subject: [PATCH] ftrace/x86: Add save_regs for i386 function calls
Add saving full regs for function tracing on i386. The saving of regs was influenced by patches sent out by Masami Hiramatsu.
--- arch/x86/include/asm/ftrace.h | 2 - arch/x86/kernel/entry_32.S | 68 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/ftrace.c | 4 -- 3 files changed, 68 insertions(+), 6 deletions(-)
arch/x86/include/asm/ftrace.h +0 -2
@@ -40,10 +40,8 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 -#ifdef CONFIG_X86_64 #define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif -#endif #ifndef __ASSEMBLY__extern void mcount (void );
arch/x86/kernel/entry_32.S +68 -0
80 lines not on this page · raw message
arch/x86/kernel/ftrace.c +0 -4
@@ -206,7 +206,6 @@ static int ftrace_modify_code(unsigned long ip, unsigned const char *old_code, unsigned const char *new_code); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* * Should never be called: * As it is only called by __ftrace_replace_code() which is called by
@@ -221,7 +220,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,WARN_ON (1 );return -EINVAL ; } -#endif int ftrace_update_ftrace_func (ftrace_func_t func) {
@@ -237,7 +235,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ret =ftrace_modify_code (ip, old, new); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* Also update the regs callback function */ if (!ret) { ip = (unsigned long )(&ftrace_regs_call);
@@ -245,7 +242,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) new =ftrace_call_replace (ip, (unsigned long )func); ret =ftrace_modify_code (ip, old, new); } -#endif atomic_dec (&modifying_ftrace_code);
Signature · 1 line
1.7.3.4
Re: Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 21 lines · Steven Rostedt
Quoted 9 lines · Masami Hiramatsu
/*
*X86_32CPUs don't save ss and esp if the CPU is already in kernel mode
* when it traps. The previous stack will be directly underneath the saved
* registers, and 'sp/ss' won't even have been saved. Thus the '®s->sp'. *
* This is valid only for kernel mode traps.
*/
static inline unsigned longkernel_stack_pointer(struct pt_regs *regs){Quoted 6 lines
#ifdef CONFIG_X86_32 return (unsigned long)(®s->sp); #else return regs->sp;#endif
}I found that
regs_get_register()doesn't honor this either. Thus, kprobes in tracing gets this:
Quoted 10 lines
# echo 'p:ftrace sys_read+4 s=%sp' > /debug/tracing/kprobe_events
# echo 1 > /debug/tracing/events/kprobes/enable
# cat trace
sshd-1345 [000] d... 489.117168: ftrace: (sys_read+0x4/0x70) s=b7e96768
sshd-1345 [000] d... 489.117191: ftrace: (sys_read+0x4/0x70) s=b7e96768
cat-1447 [000] d... 489.117392: ftrace: (sys_read+0x4/0x70) s=5a7
cat-1447 [001] d... 489.118023: ftrace: (sys_read+0x4/0x70) s=b77ad05f
less-1448 [000] d... 489.118079: ftrace: (sys_read+0x4/0x70) s=b7762e06
less-1448 [000] d... 489.118117: ftrace: (sys_read+0x4/0x70) s=b7764970Yes, that is by design, since I made it so. :) Instead of %sp, kprobe tracer provides $stack special argument for stack address, because "sp" is not always means the stack address on every arch.
Thanks,
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: [email protected]
Steven Rostedt
maintainerRe: Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 14 lines · Masami Hiramatsu
Quoted 13 lines
I found that
regs_get_register()doesn't honor this either. Thus, kprobes in tracing gets this:# echo 'p:ftrace sys_read+4 s=%sp' > /debug/tracing/kprobe_events # echo 1 > /debug/tracing/events/kprobes/enable # cat trace sshd-1345 [000] d... 489.117168: ftrace: (sys_read+0x4/0x70) s=b7e96768 sshd-1345 [000] d... 489.117191: ftrace: (sys_read+0x4/0x70) s=b7e96768 cat-1447 [000] d... 489.117392: ftrace: (sys_read+0x4/0x70) s=5a7 cat-1447 [001] d... 489.118023: ftrace: (sys_read+0x4/0x70) s=b77ad05f less-1448 [000] d... 489.118079: ftrace: (sys_read+0x4/0x70) s=b7762e06 less-1448 [000] d... 489.118117: ftrace: (sys_read+0x4/0x70) s=b7764970
Quoted 4 lines
Yes, that is by design, since I made it so. :) Instead of %sp, kprobe tracer provides $stack special argument for stack address, because "sp" is not always means the stack address on every arch.
But is that useful? Wouldn't the actual stack pointer be more informative?
-- Steve
Re: Re: Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 16 lines · Steven Rostedt
Quoted 14 lines · Masami Hiramatsu
Quoted 13 lines
I found that
regs_get_register()doesn't honor this either. Thus, kprobes in tracing gets this:# echo 'p:ftrace sys_read+4 s=%sp' > /debug/tracing/kprobe_events # echo 1 > /debug/tracing/events/kprobes/enable # cat trace sshd-1345 [000] d... 489.117168: ftrace: (sys_read+0x4/0x70) s=b7e96768 sshd-1345 [000] d... 489.117191: ftrace: (sys_read+0x4/0x70) s=b7e96768 cat-1447 [000] d... 489.117392: ftrace: (sys_read+0x4/0x70) s=5a7 cat-1447 [001] d... 489.118023: ftrace: (sys_read+0x4/0x70) s=b77ad05f less-1448 [000] d... 489.118079: ftrace: (sys_read+0x4/0x70) s=b7762e06 less-1448 [000] d... 489.118117: ftrace: (sys_read+0x4/0x70) s=b7764970
Quoted 7 lines
Quoted 4 lines
Yes, that is by design, since I made it so. :) Instead of %sp, kprobe tracer provides $stack special argument for stack address, because "sp" is not always means the stack address on every arch.
But is that useful? Wouldn't the actual stack pointer be more informative?
It is just FYI :). I rather like your "%sp" enhancement than current meaningless "%sp" on i386...
However, I think "$stack" is more general and informative for users, thus, at least perf probe uses it for getting variables from stack.
Thank you,
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: [email protected]
Steven Rostedt
maintainerRe: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
In reply to Steven RostedtOn Fri, 2012-07-13 at 14:47 -0400, Steven Rostedt wrote:
Masami, can you give your Reviewed-by tag for this version? Or is there something else needing to be fixed?
Thanks!
-- Steve
Quoted 153 lines
From: Steven Rostedt <[email protected]>
Date: Tue, 5 Jun 2012 20:00:11 -0400
Subject: [PATCH] ftrace/x86: Addsave_regsfor i386 function callsAdd saving full regs for function tracing on i386. The saving of regs was influenced by patches sent out by Masami Hiramatsu.
Cc Masami Hiramatsu <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- arch/x86/include/asm/ftrace.h | 2 - arch/x86/kernel/entry_32.S | 68 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/ftrace.c | 4 -- 3 files changed, 68 insertions(+), 6 deletions(-)arch/x86/include/asm/ftrace.h +0
-2@@ -40,10 +40,8 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 -#ifdef CONFIG_X86_64 #define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif -#endif #ifndef __ASSEMBLY__extern void mcount (void );arch/x86/kernel/entry_32.S +68
-0@@ -1123,6 +1123,7 @@ ftrace_call: popl %edx popl %ecx popl %eax +ftrace_ret: #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl ftrace_graph_call ftrace_graph_call:@@ -1134,6 +1135,73 @@ ftrace_stub: ret END(ftrace_caller) +ENTRY(ftrace_regs_caller) + pushf /* push flags before compare (in cs location) */ + cmpl $0, function_trace_stop + jne ftrace_restore_flags + + /* + * i386 does not save SS and ESP when coming from kernel. + * Instead, to get sp, ®s->sp is used (see ptrace.h). + * Unfortunately, that means eflags must be at the same location + * as the current return ip is. We move the return ip into the + * ip location, and move flags into the return ip location. + */ + pushl 4(%esp) /* save return ip into ip slot */ + subl $MCOUNT_INSN_SIZE, (%esp) /* Adjust ip */ + + pushl $0 /* Load 0 into orig_ax */ + pushl %gs + pushl %fs + pushl %es + pushl %ds + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + + movl 13*4(%esp), %eax /* Get the saved flags */ + movl %eax, 14*4(%esp) /* Move saved flags into regs->flags location */ + /* clobbering return ip */ + movl $__KERNEL_CS,13*4(%esp) + + movl 12*4(%esp), %eax /* Load ip (1st parameter) */ + movl 0x4(%ebp), %edx /* Load parent ip (2cd parameter) */ + lea (%esp), %ecx + pushl %ecx /* Save pt_regs as 4th parameter */ + leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */ + +GLOBAL(ftrace_regs_call) + call ftrace_stub + + addl $4, %esp /* Skip pt_regs */ + movl 14*4(%esp), %eax /* Move flags back into cs */ + movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */ + movl 12*4(%esp), %eax /* Get return ip from regs->ip */ + addl $MCOUNT_INSN_SIZE, %eax + movl %eax, 14*4(%esp) /* Put return ip back for ret */ + + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + popl %ds + popl %es + popl %fs + popl %gs + addl $8, %esp /* Skip orig_ax and ip */ + popf /* Pop flags at end (no addl to corrupt flags) */ + jmp ftrace_ret + +ftrace_restore_flags: + popf + jmp ftrace_stub #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount)arch/x86/kernel/ftrace.c +0
-4@@ -206,7 +206,6 @@ static int ftrace_modify_code(unsigned long ip, unsigned const char *old_code, unsigned const char *new_code); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* * Should never be called: * As it is only called by __ftrace_replace_code() which is called by @@ -221,7 +220,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,WARN_ON (1 );return -EINVAL ; } -#endif int ftrace_update_ftrace_func (ftrace_func_t func) {@@ -237,7 +235,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ret =ftrace_modify_code (ip, old, new); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* Also update the regs callback function */ if (!ret) { ip = (unsigned long )(&ftrace_regs_call);@@ -245,7 +242,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) new =ftrace_call_replace (ip, (unsigned long )func); ret =ftrace_modify_code (ip, old, new); } -#endif atomic_dec (&modifying_ftrace_code);
Masami Hiramatsu
Reviewed-byRe: Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 4 lines · Steven Rostedt
On Fri, 2012-07-13 at 14:47 -0400, Steven Rostedt wrote:
Masami, can you give your Reviewed-by tag for this version? Or is there something else needing to be fixed?
No, that is OK for me. I've just missed that...
Thank you!
Quoted 166 lines
Thanks!
-- Steve
Quoted 146 lines
From: Steven Rostedt <[email protected]>
Date: Tue, 5 Jun 2012 20:00:11 -0400
Subject: [PATCH] ftrace/x86: Addsave_regsfor i386 function callsAdd saving full regs for function tracing on i386. The saving of regs was influenced by patches sent out by Masami Hiramatsu.
Cc Masami Hiramatsu <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- arch/x86/include/asm/ftrace.h | 2 - arch/x86/kernel/entry_32.S | 68 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/ftrace.c | 4 -- 3 files changed, 68 insertions(+), 6 deletions(-)arch/x86/include/asm/ftrace.h +0
-2@@ -40,10 +40,8 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 -#ifdef CONFIG_X86_64 #define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif -#endif #ifndef __ASSEMBLY__extern void mcount (void );arch/x86/kernel/entry_32.S +68
-0@@ -1123,6 +1123,7 @@ ftrace_call: popl %edx popl %ecx popl %eax +ftrace_ret: #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl ftrace_graph_call ftrace_graph_call:@@ -1134,6 +1135,73 @@ ftrace_stub: ret END(ftrace_caller) +ENTRY(ftrace_regs_caller) + pushf /* push flags before compare (in cs location) */ + cmpl $0, function_trace_stop + jne ftrace_restore_flags + + /* + * i386 does not save SS and ESP when coming from kernel. + * Instead, to get sp, ®s->sp is used (see ptrace.h). + * Unfortunately, that means eflags must be at the same location + * as the current return ip is. We move the return ip into the + * ip location, and move flags into the return ip location. + */ + pushl 4(%esp) /* save return ip into ip slot */ + subl $MCOUNT_INSN_SIZE, (%esp) /* Adjust ip */ + + pushl $0 /* Load 0 into orig_ax */ + pushl %gs + pushl %fs + pushl %es + pushl %ds + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + + movl 13*4(%esp), %eax /* Get the saved flags */ + movl %eax, 14*4(%esp) /* Move saved flags into regs->flags location */ + /* clobbering return ip */ + movl $__KERNEL_CS,13*4(%esp) + + movl 12*4(%esp), %eax /* Load ip (1st parameter) */ + movl 0x4(%ebp), %edx /* Load parent ip (2cd parameter) */ + lea (%esp), %ecx + pushl %ecx /* Save pt_regs as 4th parameter */ + leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */ + +GLOBAL(ftrace_regs_call) + call ftrace_stub + + addl $4, %esp /* Skip pt_regs */ + movl 14*4(%esp), %eax /* Move flags back into cs */ + movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */ + movl 12*4(%esp), %eax /* Get return ip from regs->ip */ + addl $MCOUNT_INSN_SIZE, %eax + movl %eax, 14*4(%esp) /* Put return ip back for ret */ + + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + popl %ds + popl %es + popl %fs + popl %gs + addl $8, %esp /* Skip orig_ax and ip */ + popf /* Pop flags at end (no addl to corrupt flags) */ + jmp ftrace_ret + +ftrace_restore_flags: + popf + jmp ftrace_stub #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount)arch/x86/kernel/ftrace.c +0
-3@@ -206,7 +206,6 @@ static int ftrace_modify_code(unsigned long ip, unsigned const char *old_code, unsigned const char *new_code); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* * Should never be called: * As it is only called by __ftrace_replace_code() which is called by @@ -221,7 +220,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,WARN_ON (1 );return -EINVAL ; } -#endif int ftrace_update_ftrace_func (ftrace_func_t func) {@@ -237,7 +235,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ret =ftrace_modify_code (ip, old, new); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* Also update the regs callback function */ if (!ret) { ip = (unsigned long )(&ftrace_regs_call);arch/x86/kernel/ftrace.c int ftrace_update_ftrace_func(ftrace_func_t func) · line 247
Quoted 7 lines
arch/x86/kernel/ftrace.c +0
-1@@ -245,7 +242,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) new =ftrace_call_replace (ip, (unsigned long )func); ret =ftrace_modify_code (ip, old, new); } -#endif atomic_dec (&modifying_ftrace_code);--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: [email protected]
Steven Rostedt
maintainerRe: Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 12 lines · Masami Hiramatsu
Quoted 4 lines · Steven Rostedt
On Fri, 2012-07-13 at 14:47 -0400, Steven Rostedt wrote:
Masami, can you give your Reviewed-by tag for this version? Or is there something else needing to be fixed?
No, that is OK for me. I've just missed that...
Reviewed-by Masami Hiramatsu <[email protected]>Thank you!
Thanks! Except I have one more version. Someone offlist gave me some ideas.
Here's the diff from the previous patch.
arch/x86/kernel/entry_32.S +4 -5
@@ -1169,10 +1169,9 @@ ENTRY(ftrace_regs_caller) movl $__KERNEL_CS,13*4(%esp) movl 12*4(%esp), %eax /* Load ip (1st parameter) */ - movl 0x4(%ebp), %edx /* Load parent ip (2cd parameter) */ - lea (%esp), %ecx - pushl %ecx /* Save pt_regs as 4th parameter */ + movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */ leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */ + pushl %esp /* Save pt_regs as 4th parameter */ GLOBAL(ftrace_regs_call) call ftrace_stub
@@ -1195,8 +1194,8 @@ GLOBAL(ftrace_regs_call) popl %es popl %fs popl %gs - addl $8, %esp /* Skip orig_ax and ip */ - popf /* Pop flags at end (no addl to corrupt flags) */ + lea 8(%esp), %esp /* Skip orig_ax and ip */ + popf /* Pop flags at end */ jmp ftrace_ret ftrace_restore_flags:
Because we no longer have that 4 byte offset on the stack when we need to load the 4th parameter, we can just load the current stack pointer into the stack (pushl %esp), without the save to %ecx step.
also, because lea is faster than add (and doesn't even modify flags), I changed the last part to use lea instead of addl.
Can you give your reviewed-by tag for this too? I'd like to push this out today so we can still make 3.6.
Thanks!
-- Steve
here's the full patch:
arch/x86/include/asm/ftrace.h +0 -2
@@ -40,10 +40,8 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 -#ifdef CONFIG_X86_64 #define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif -#endif #ifndef __ASSEMBLY__extern void mcount (void );
arch/x86/kernel/entry_32.S +67 -0
79 lines not on this page · raw message
arch/x86/kernel/ftrace.c +0 -4
@@ -206,7 +206,6 @@ static int ftrace_modify_code(unsigned long ip, unsigned const char *old_code, unsigned const char *new_code); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* * Should never be called: * As it is only called by __ftrace_replace_code() which is called by
@@ -221,7 +220,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,WARN_ON (1 );return -EINVAL ; } -#endif int ftrace_update_ftrace_func (ftrace_func_t func) {
@@ -237,7 +235,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ret =ftrace_modify_code (ip, old, new); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* Also update the regs callback function */ if (!ret) { ip = (unsigned long )(&ftrace_regs_call);
@@ -245,7 +242,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) new =ftrace_call_replace (ip, (unsigned long )func); ret =ftrace_modify_code (ip, old, new); } -#endif atomic_dec (&modifying_ftrace_code);
Steven Rostedt
maintainerRe: Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 16 lines · Steven Rostedt
GLOBAL(ftrace_regs_call)arch/x86/kernel/entry_32.S +2
-2call ftrace_stub@@ -1195,8 +1194,8 @@ GLOBAL(ftrace_regs_call) popl %es popl %fs popl %gs - addl $8, %esp /* Skip orig_ax and ip */ - popf /* Pop flags at end (no addl to corrupt flags) */ + lea 8(%esp), %esp /* Skip orig_ax and ip */ + popf /* Pop flags at end */ jmp ftrace_ret ftrace_restore_flags:
Quoted 6 lines
Because we no longer have that 4 byte offset on the stack when we need to load the 4th parameter, we can just load the current stack pointer into the stack (pushl %esp), without the save to %ecx step.
also, because lea is faster than add (and doesn't even modify flags), I changed the last part to use lea instead of addl.
Now I'm told that this is not always the case (at least not for Atom), so I reverted this part and put back the addl. But can you still give you reviewed by for the first part?
Quoted 90 lines
Can you give your reviewed-by tag for this too? I'd like to push this out today so we can still make 3.6.
Thanks!
-- Steve
here's the full patch:
arch/x86/include/asm/ftrace.h +0
-2@@ -40,10 +40,8 @@#ifdef CONFIG_DYNAMIC_FTRACE #define ARCH_SUPPORTS_FTRACE_OPS 1 -#ifdef CONFIG_X86_64 #define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif -#endif #ifndef __ASSEMBLY__extern void mcount (void );arch/x86/kernel/entry_32.S +50
-0@@ -1123,6 +1123,7 @@ ftrace_call: popl %edx popl %ecx popl %eax +ftrace_ret: #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl ftrace_graph_call ftrace_graph_call:@@ -1134,6 +1135,72 @@ ftrace_stub: ret END(ftrace_caller) +ENTRY(ftrace_regs_caller) + pushf /* push flags before compare (in cs location) */ + cmpl $0, function_trace_stop + jne ftrace_restore_flags + + /* + * i386 does not save SS and ESP when coming from kernel. + * Instead, to get sp, ®s->sp is used (see ptrace.h). + * Unfortunately, that means eflags must be at the same location + * as the current return ip is. We move the return ip into the + * ip location, and move flags into the return ip location. + */ + pushl 4(%esp) /* save return ip into ip slot */ + subl $MCOUNT_INSN_SIZE, (%esp) /* Adjust ip */ + + pushl $0 /* Load 0 into orig_ax */ + pushl %gs + pushl %fs + pushl %es + pushl %ds + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + + movl 13*4(%esp), %eax /* Get the saved flags */ + movl %eax, 14*4(%esp) /* Move saved flags into regs->flags location */ + /* clobbering return ip */ + movl $__KERNEL_CS,13*4(%esp) + + movl 12*4(%esp), %eax /* Load ip (1st parameter) */ + movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */ + leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */ + pushl %esp /* Save pt_regs as 4th parameter */ + +GLOBAL(ftrace_regs_call) + call ftrace_stub + + addl $4, %esp /* Skip pt_regs */ + movl 14*4(%esp), %eax /* Move flags back into cs */ + movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */ + movl 12*4(%esp), %eax /* Get return ip from regs->ip */ + addl $MCOUNT_INSN_SIZE, %eax + movl %eax, 14*4(%esp) /* Put return ip back for ret */ + + popl %ebx
arch/x86/kernel/entry_32.S ftrace_stub: · line 1196
Quoted 10 lines
arch/x86/kernel/entry_32.S +10
-0+ popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + popl %ds + popl %es + popl %fs + popl %gs
+ addl $8, %esp /* Skip orig_ax and ip */
+ popf /* Pop flags at end (no addl to corrupt flags) */
The above has been changed to this again.
-- Steve
Quoted 46 lines
arch/x86/kernel/entry_32.S +5
-0+ jmp ftrace_ret + +ftrace_restore_flags: + popf + jmp ftrace_stub #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount)arch/x86/kernel/ftrace.c +0
-4@@ -206,7 +206,6 @@ static int ftrace_modify_code(unsigned long ip, unsigned const char *old_code, unsigned const char *new_code); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* * Should never be called: * As it is only called by __ftrace_replace_code() which is called by @@ -221,7 +220,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,WARN_ON (1 );return -EINVAL ; } -#endif int ftrace_update_ftrace_func (ftrace_func_t func) {@@ -237,7 +235,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ret =ftrace_modify_code (ip, old, new); -#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS /* Also update the regs callback function */ if (!ret) { ip = (unsigned long )(&ftrace_regs_call);@@ -245,7 +242,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) new =ftrace_call_replace (ip, (unsigned long )func); ret =ftrace_modify_code (ip, old, new); } -#endif atomic_dec (&modifying_ftrace_code);
H. Peter Anvin
reviewerRe: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 8 lines · Steven Rostedt
Quoted 3 lines
also, because lea is faster than add (and doesn't even modify flags), I changed the last part to use lea instead of addl.
Now I'm told that this is not always the case (at least not for Atom), so I reverted this part and put back the addl. But can you still give you reviewed by for the first part?
lea is not typically faster than add, but in the case of Atom, it is done in an earlier pipeline stage (AGU instead of ALU) which means lea is faster if its inputs are already available as address expressions and is consumed by address expressions; the goal is to avoid the ALU->AGU forwarding latency.
-hpa
Steven Rostedt
maintainerRe: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 5 lines · H. Peter Anvin
lea is not typically faster than add, but in the case of Atom, it is done in an earlier pipeline stage (AGU instead of ALU) which means lea is faster if its inputs are already available as address expressions and is consumed by address expressions; the goal is to avoid the
ALU->AGUforwarding latency.
Well, the question is, which is faster:
lea 8(%esp), %esp addl $8, %esp
Basically, all we want to do is add 8 to the stack pointer. And this is for the x86_32 version of whatever hardware is in use.
-- Steve
H. Peter Anvin
reviewerRe: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 8 lines · Steven Rostedt
Quoted 5 lines · H. Peter Anvin
lea is not typically faster than add, but in the case of Atom, it is done in an earlier pipeline stage (AGU instead of ALU) which means lea is faster if its inputs are already available as address expressions and is consumed by address expressions; the goal is to avoid the
ALU->AGUforwarding latency.
Quoted 8 lines
Well, the question is, which is faster:
lea 8(%esp), %esp addl $8, %espBasically, all we want to do is add 8 to the stack pointer. And this is for the
x86_32version of whatever hardware is in use.
What I'm telling you is that it depends on the context.
An address expression needs to be ready in the AGU; a piece of data comes from the ALU. Whenever something moves from the ALU to the AGU, there is a penalty. There is no penalty to move from the AGU to the ALU, since the ALU is in a later stage.
I *believe* the stack adjustments push/pop are done in the AGU, but I have to double-check.
-hpa
Steven Rostedt
maintainerRe: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
Quoted 7 lines · H. Peter Anvin
Quoted 3 lines · Steven Rostedt
Basically, all we want to do is add 8 to the stack pointer. And this is for the
x86_32version of whatever hardware is in use.What I'm telling you is that it depends on the context.
It doesn't really matter anyway. My questions are more academic than practical, as I'm just sticking with addl. Quibbling over addl or lea is pointless, as addl at least shows us what we want to actually do: add 8 to the stack pointer.
-- Steve
Steven Rostedt
maintainerRe: Re: [RFC][PATCH 2/4 v4] ftrace/x86: Add save_regs for i386 function calls
In reply to Steven RostedtQuoted 25 lines · Steven Rostedt
Quoted 12 lines · Masami Hiramatsu
Quoted 4 lines · Steven Rostedt
On Fri, 2012-07-13 at 14:47 -0400, Steven Rostedt wrote:
Masami, can you give your Reviewed-by tag for this version? Or is there something else needing to be fixed?
No, that is OK for me. I've just missed that...
Reviewed-by Masami Hiramatsu <[email protected]>Thank you!
Thanks! Except I have one more version. Someone offlist gave me some ideas.
Here's the diff from the previous patch.
arch/x86/kernel/entry_32.S +0
-0@@ -1169,10 +1169,9 @@ ENTRY(ftrace_regs_caller) movl $__KERNEL_CS,13*4(%esp)
arch/x86/kernel/entry_32.S ENTRY(ftrace_regs_caller) · line 1176
Quoted 10 lines
arch/x86/kernel/entry_32.S +2
-3movl 12*4(%esp), %eax /* Load ip (1st parameter) */ - movl 0x4(%ebp), %edx /* Load parent ip (2cd parameter) */ - lea (%esp), %ecx - pushl %ecx /* Save pt_regs as 4th parameter */ + movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */ leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */ + pushl %esp /* Save pt_regs as 4th parameter */ GLOBAL(ftrace_regs_call)
I'm adding this as a separate patch under Uros's name.
I'll be posting the full series for pulling either tonight or tomorrow, depending on how it handles all my stress tests.
-- Steve
[tip:perf/core] ftrace/x86_32: Simplify parameter setup for ftrace_regs_caller
In reply to Steven RostedtCommit-ID: e4ea3f6b1bf3d489674a3660db652636e50186f9 Gitweb: http://git.kernel.org/tip/e4ea3f6b1bf3d489674a3660db652636e50186f9 Author: Uros Bizjak <[email protected]> AuthorDate: Thu, 19 Jul 2012 13:04:47 -0400 Committer: Steven Rostedt <[email protected]> CommitDate: Tue, 31 Jul 2012 10:29:34 -0400
ftrace/x86_32: Simplify parameter setup for ftrace_regs_caller
The final position of the stack after saving regs and setting up the parameters for ftrace_regs_call, is the position of the pt_regs needed for the 4th parameter. Instead of saving it into a temporary reg and pushing the reg, simply push the stack pointer.
--- arch/x86/kernel/entry_32.S | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
arch/x86/kernel/entry_32.S +2 -3
@@ -1169,10 +1169,9 @@ ENTRY(ftrace_regs_caller) movl $__KERNEL_CS,13*4(%esp) movl 12*4(%esp), %eax /* Load ip (1st parameter) */ - movl 0x4(%ebp), %edx /* Load parent ip (2cd parameter) */ - lea (%esp), %ecx - pushl %ecx /* Save pt_regs as 4th parameter */ + movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */ leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */ + pushl %esp /* Save pt_regs as 4th parameter */ GLOBAL(ftrace_regs_call) call ftrace_stub
Steven Rostedt
maintainerRFC PATCH v4 3/4 ftrace/x86: Remove function_trace_stop check from graph caller
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
The graph caller is called by the mcount callers, which already does the check against the function_trace_stop variable. No reason to check it again.
--- arch/x86/kernel/entry_32.S | 3 --- arch/x86/kernel/entry_64.S | 3 --- 2 files changed, 6 deletions(-)
arch/x86/kernel/entry_32.S +0 -3
@@ -1232,9 +1232,6 @@ END(mcount) #ifdef CONFIG_FUNCTION_GRAPH_TRACER ENTRY(ftrace_graph_caller) - cmpl $0, function_trace_stop - jne ftrace_stub - pushl %eax pushl %ecx pushl %edx
arch/x86/kernel/entry_64.S +0 -3
@@ -213,9 +213,6 @@ END(mcount) #ifdef CONFIG_FUNCTION_GRAPH_TRACER ENTRY(ftrace_graph_caller) - cmpl $0, function_trace_stop - jne ftrace_stub - MCOUNT_SAVE_FRAME leaq 8(%rbp), %rdi
Signature · 1 line
1.7.10
[tip:perf/core] ftrace/x86: Remove function_trace_stop check from graph caller
Commit-ID: 5767cfeaa9ec7b67c802143394f3ad9f8b174eb8 Gitweb: http://git.kernel.org/tip/5767cfeaa9ec7b67c802143394f3ad9f8b174eb8 Author: Steven Rostedt <[email protected]> AuthorDate: Tue, 3 Jul 2012 16:16:09 -0400 Committer: Steven Rostedt <[email protected]> CommitDate: Tue, 31 Jul 2012 10:29:51 -0400
ftrace/x86: Remove function_trace_stop check from graph caller
The graph caller is called by the mcount callers, which already does the check against the function_trace_stop variable. No reason to check it again.
--- arch/x86/kernel/entry_32.S | 3 --- arch/x86/kernel/entry_64.S | 3 --- 2 files changed, 0 insertions(+), 6 deletions(-)
arch/x86/kernel/entry_32.S +0 -3
@@ -1241,9 +1241,6 @@ END(mcount) #ifdef CONFIG_FUNCTION_GRAPH_TRACER ENTRY(ftrace_graph_caller) - cmpl $0, function_trace_stop - jne ftrace_stub - pushl %eax pushl %ecx pushl %edx
arch/x86/kernel/entry_64.S +0 -3
@@ -213,9 +213,6 @@ END(mcount) #ifdef CONFIG_FUNCTION_GRAPH_TRACER ENTRY(ftrace_graph_caller) - cmpl $0, function_trace_stop - jne ftrace_stub - MCOUNT_SAVE_FRAME leaq 8(%rbp), %rdi
Steven Rostedt
maintainerRFC PATCH v4 4/4 ftrace/x86_64: Add recursion protection inside mcount caller
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
As more users of function tracing is occurring (perf, kprobes, etc) there's more chances that the users do not sufficiently protect against recursion. As it is simple to protect against it either at the mcount call site, or by the "list function", an arch can now add protection inside the mcount trampoline and define ARCH_SUPPORTS_FTRACE_RECURSION.
If ARCH_SUPPORTS_FTRACE_RECURSION is not defined by the arch (inside the asm/ftrace.h), the FTRACE_FORCE_LIST_FUNC is set to 1, which will always enable the list function (the function used to call multiple function trace callbacks when more than one is register) even if there's only one function register. This is because the list function provides all the required features (like recursion protection) for function tracing. If the arch does not support all features, the list function is used to make sure they are supported.
--- arch/x86/include/asm/ftrace.h | 2 ++ arch/x86/kernel/entry_32.S | 28 ++++++++++++++++++++++++++-- arch/x86/kernel/entry_64.S | 30 +++++++++++++++++++++++++++--- arch/x86/kernel/ftrace.c | 7 +++++-- include/linux/ftrace.h | 2 +- 5 files changed, 61 insertions(+), 8 deletions(-)
arch/x86/include/asm/ftrace.h +2 -0
@@ -43,6 +43,8 @@#define ARCH_SUPPORTS_FTRACE_SAVE_REGS #endif +#define ARCH_SUPPORTS_FTRACE_RECURSION +#ifndef __ASSEMBLY__extern void mcount (void );extern atomic_t modifying_ftrace_code;
arch/x86/kernel/entry_32.S +26 -2
@@ -1106,6 +1106,12 @@ ENTRY(ftrace_caller) cmpl $0, function_trace_stop jne ftrace_stub + /* Check for recursion */ + cmpl $0, PER_CPU_VAR(ftrace_recursion) + jne ftrace_stub + + movl $1, PER_CPU_VAR(ftrace_recursion) + pushl %eax pushl %ecx pushl %edx
@@ -1127,8 +1133,11 @@ ftrace_ret: #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl ftrace_graph_call ftrace_graph_call: - jmp ftrace_stub + jmp ftrace_graph_finish +.globl ftrace_graph_finish +ftrace_graph_finish: #endif + movl $0, PER_CPU_VAR(ftrace_recursion) .globl ftrace_stub ftrace_stub:
@@ -1140,6 +1149,12 @@ ENTRY(ftrace_regs_caller) cmpl $0, function_trace_stop jne ftrace_restore_flags + /* Check for recursion */ + cmpl $0, PER_CPU_VAR(ftrace_recursion) + jne ftrace_restore_flags + + movl $1, PER_CPU_VAR(ftrace_recursion) + pushl %esp /* Save stack in sp location */ subl $4, (%esp) /* Adjust saved stack to skip saved flags */ pushl 4(%esp) /* Save flags in correct position */
@@ -1198,6 +1213,12 @@ ENTRY(mcount) cmpl $0, function_trace_stop jne ftrace_stub + /* Check for recursion */ + cmpl $0, PER_CPU_VAR(ftrace_recursion) + jne ftrace_stub + + movl $1, PER_CPU_VAR(ftrace_recursion) + cmpl $ftrace_stub, ftrace_trace_function jnz trace #ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -1206,7 +1227,10 @@ ENTRY(mcount) cmpl $ftrace_graph_entry_stub, ftrace_graph_entry jnz ftrace_graph_caller +ftrace_graph_finish: #endif + movl $0, PER_CPU_VAR(ftrace_recursion) + .globl ftrace_stub ftrace_stub: ret
@@ -1243,7 +1267,7 @@ ENTRY(ftrace_graph_caller) popl %edx popl %ecx popl %eax - ret + jmp ftrace_graph_finish END(ftrace_graph_caller) .globl return_to_handler
arch/x86/kernel/entry_64.S +27 -3
@@ -77,6 +77,8 @@ END(mcount) .macro ftrace_caller_setup skip=0 MCOUNT_SAVE_FRAME \skip + movl $1, PER_CPU_VAR(ftrace_recursion) + /* Load the ftrace_ops into the 3rd parameter */ leaq function_trace_op, %rdx
@@ -92,6 +94,10 @@ ENTRY(ftrace_caller) cmpl $0, function_trace_stop jne ftrace_stub + /* Check for recursion */ + cmpl $0, PER_CPU_VAR(ftrace_recursion) + jne ftrace_stub + ftrace_caller_setup /* regs go into 4th parameter (but make it NULL) */ movq $0, %rcx
@@ -104,9 +110,12 @@ ftrace_return: #ifdef CONFIG_FUNCTION_GRAPH_TRACER GLOBAL(ftrace_graph_call) - jmp ftrace_stub + jmp ftrace_graph_finish +GLOBAL(ftrace_graph_finish) #endif + movl $0, PER_CPU_VAR(ftrace_recursion) + GLOBAL(ftrace_stub) retq END(ftrace_caller)
@@ -119,6 +128,10 @@ ENTRY(ftrace_regs_caller) cmpl $0, function_trace_stop jne ftrace_restore_flags + /* Check for recursion */ + cmpl $0, PER_CPU_VAR(ftrace_recursion) + jne ftrace_restore_flags + /* skip=8 to skip flags saved in SS */ ftrace_caller_setup 8
@@ -181,17 +194,28 @@ ENTRY(mcount) cmpl $0, function_trace_stop jne ftrace_stub + /* Check for recursion */ + cmpl $0, PER_CPU_VAR(ftrace_recursion) + jne ftrace_stub + + movl $1, PER_CPU_VAR(ftrace_recursion) + cmpq $ftrace_stub, ftrace_trace_function jnz trace +ftrace_return: + #ifdef CONFIG_FUNCTION_GRAPH_TRACER cmpq $ftrace_stub, ftrace_graph_return jnz ftrace_graph_caller cmpq $ftrace_graph_entry_stub, ftrace_graph_entry jnz ftrace_graph_caller +ftrace_graph_finish: #endif + movl $0, PER_CPU_VAR(ftrace_recursion) + GLOBAL(ftrace_stub) retq
@@ -206,7 +230,7 @@ trace: MCOUNT_RESTORE_FRAME - jmp ftrace_stub + jmp ftrace_return END(mcount) #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_TRACER */
@@ -224,7 +248,7 @@ ENTRY(ftrace_graph_caller) MCOUNT_RESTORE_FRAME - retq + jmp ftrace_graph_finish END(ftrace_graph_caller) GLOBAL(return_to_handler)
arch/x86/kernel/ftrace.c +5 -2
@@ -28,6 +28,8 @@#include <asm/ftrace.h> #include <asm/nops.h> +DEFINE_PER_CPU (int, ftrace_recursion); +#ifdef CONFIG_DYNAMIC_FTRACE int ftrace_arch_code_modify_prepare (void )
@@ -664,6 +666,7 @@ int __init ftrace_dyn_arch_init(void *data)#ifdef CONFIG_DYNAMIC_FTRACE extern void ftrace_graph_call (void ); +extern void ftrace_graph_finish (void );static int ftrace_mod_jmp (unsigned long ip,int old_offset,int new_offset)
@@ -689,7 +692,7 @@ int ftrace_enable_ftrace_graph_caller(void)unsigned long ip = (unsigned long )(&ftrace_graph_call);int old_offset, new_offset; - old_offset = (unsigned long )(&ftrace_stub) - (ip +MCOUNT_INSN_SIZE ); + old_offset = (unsigned long )(&ftrace_graph_finish) - (ip +MCOUNT_INSN_SIZE ); new_offset = (unsigned long )(&ftrace_graph_caller) - (ip +MCOUNT_INSN_SIZE );return ftrace_mod_jmp (ip, old_offset, new_offset);
@@ -701,7 +704,7 @@ int ftrace_disable_ftrace_graph_caller(void)int old_offset, new_offset; old_offset = (unsigned long )(&ftrace_graph_caller) - (ip +MCOUNT_INSN_SIZE ); - new_offset = (unsigned long )(&ftrace_stub) - (ip +MCOUNT_INSN_SIZE ); + new_offset = (unsigned long )(&ftrace_graph_finish) - (ip +MCOUNT_INSN_SIZE );return ftrace_mod_jmp (ip, old_offset, new_offset); }
include/linux/ftrace.h +1 -1
@@ -34,7 +34,7 @@* does. Or at least does enough to prevent any unwelcomed side effects. */ #if !defined(CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST ) || \ - !ARCH_SUPPORTS_FTRACE_OPS + !ARCH_SUPPORTS_FTRACE_OPS || !defined(ARCH_SUPPORTS_FTRACE_RECURSION )# define FTRACE_FORCE_LIST_FUNC 1#else # define FTRACE_FORCE_LIST_FUNC 0
Signature · 1 line
1.7.10