Skip to contentSkip to conversation

ftrace/x86_32: Ftrace cleanup and add support for -mfentry

RFC PATCH Superseded Steven Rostedt 3 participants 14 messages Mar 15, 2017 – Mar 16, 2017

Subsystems (4)

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Steven Rostedt

author maintainer
#0 lore raw

cover ftrace/x86_32: Ftrace cleanup and add support for -mfentry

With the issues of gcc screwing around with the mcount stack frame causing function graph tracer to panic on x86_32, and with Linus saying that we should start deprecating mcount (at least on x86), I figured that x86_32 needs to support fentry.

First, I renamed mcount_64.S to ftrace_64.S (hmm, my subject says ftrace.S, oh well, this is still RFC, I'll fix that before posting). As we want to get away from mcount, having the ftrace code in a file called mcount seems rather backwards.

Next I moved the ftrace code out of entry_32.S. It's not in entry_64.S and it does not belong in entry_32.S.

I noticed that the x86_32 code has the same issue as the x86_64 did in the past with respect to a stack frame. I fixed that just for the main ftrace_caller. The ftrace_regs_caller is rather special, and so is function graph tracing.

I realized the ftrace_regs_caller code was complex due to me aggressively saving flags, even though I could still do push, lea and mov without changing them. That made the logic a little nicer.

Finally I added the fentry code.

I tested this (and I'm currently testing it) with an old compiler (for mcount) with and without FRAME_POINTER set. I also did it with a new compiler (with fentry), with and without FRAME_POINTER. I tested function tracing, stack tracing, function_graph tracing, and kprobes (as that uses the ftrace_regs_caller). So far this works. I'm still testing but I'm confident enough with the current code to post an RFC.

Thoughts?

-- Steve

Steven Rostedt (VMware) (5):
x86/ftrace: Rename mcount_64.S to ftrace.S
ftrace/x86-32: Move the ftrace specific code out of entry_32.S ftrace/x86_32: Add stack frame pointer to ftrace_caller ftrace/x86_32: Clean up ftrace_regs_caller
ftrace/x86-32: Add -mfentry support to x86_32 with DYNAMIC_FTRACE set

----

 Makefile                                     |  12 +-
 arch/x86/Kconfig                             |   2 +-
 arch/x86/entry/entry_32.S                    | 168 -----------------
 arch/x86/kernel/Makefile                     |   5 +-
 arch/x86/kernel/ftrace_32.S                  | 257 +++++++++++++++++++++++++++
 arch/x86/kernel/{mcount_64.S => ftrace_64.S} |   0
 6 files changed, 267 insertions(+), 177 deletions(-)
 create mode 100644 arch/x86/kernel/ftrace_32.S
 rename arch/x86/kernel/{mcount_64.S => ftrace_64.S} (100%)
author maintainer
#1 lore raw

RFC PATCH 1/5 x86/ftrace: Rename mcount_64.S to ftrace.S

From: "Steven Rostedt (VMware)" <[email protected]>

With the advent of -mfentry that uses the new "fentry" hook over mcount, the mcount name is obsolete. Having the code file that ftrace hooks into called "mcount*.S" is rather misleading. Rename it to ftrace.S

---
 arch/x86/kernel/Makefile                     | 4 ++--
 arch/x86/kernel/{mcount_64.S => ftrace_64.S} | 0
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename arch/x86/kernel/{mcount_64.S => ftrace_64.S} (100%)
arch/x86/kernel/Makefile +2 -2
index 84c00592d359..d3743a37e990 100644
@@ -27,7 +27,7 @@ KASAN_SANITIZE_stacktrace.o := n
 
 OBJECT_FILES_NON_STANDARD_head_$(BITS).o		:= y
 OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o	:= y
-OBJECT_FILES_NON_STANDARD_mcount_$(BITS).o		:= y
+OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o		:= y
 OBJECT_FILES_NON_STANDARD_test_nx.o			:= y
 
 # If instrumentation of this dir is enabled, boot hangs during first second.
@@ -46,7 +46,7 @@ obj-$(CONFIG_MODIFY_LDT_SYSCALL)	+= ldt.o
 obj-y			+= setup.o x86_init.o i8259.o irqinit.o jump_label.o
 obj-$(CONFIG_IRQ_WORK)  += irq_work.o
 obj-y			+= probe_roms.o
-obj-$(CONFIG_X86_64)	+= sys_x86_64.o mcount_64.o
+obj-$(CONFIG_X86_64)	+= sys_x86_64.o ftrace_64.o
 obj-$(CONFIG_X86_ESPFIX64)	+= espfix_64.o
 obj-$(CONFIG_SYSFS)	+= ksysfs.o
 obj-y			+= bootflag.o e820.o
arch/x86/kernel/ftrace_64.S renamed from arch/x86/kernel/mcount_64.S +0 -0
similarity index 100%
rename from arch/x86/kernel/mcount_64.S
rename to arch/x86/kernel/ftrace_64.S
Signature · 1 line
2.10.2
author maintainer
#2 lore raw

RFC PATCH 2/5 ftrace/x86-32: Move the ftrace specific code out of entry_32.S

In reply to Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

The function tracing hook code for ftrace is not an entry point from userspace and does not belong in the entry_*.S files. It has already been moved out of entry_64.S. This moves it out of entry_32.S

---
 Makefile                    |  12 +--
 arch/x86/entry/entry_32.S   | 168 ------------------------------------------
 arch/x86/kernel/Makefile    |   1 +
 arch/x86/kernel/ftrace_32.S | 176 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+), 174 deletions(-)
 create mode 100644 arch/x86/kernel/ftrace_32.S
Makefile +6 -6
index 165cf9783a5d..7e3aadeea0c1 100644
@@ -653,6 +653,12 @@ KBUILD_CFLAGS += $(call cc-ifversion, -lt, 0409, \
 # Tell gcc to never replace conditional load with a non-conditional one
 KBUILD_CFLAGS	+= $(call cc-option,--param=allow-store-data-races=0)
 
+# check for 'asm goto'
+ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y)
+	KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
+	KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO
+endif
+
 include scripts/Makefile.gcc-plugins
 
 ifdef CONFIG_READABLE_ASM
@@ -798,12 +804,6 @@ KBUILD_CFLAGS   += $(call cc-option,-Werror=incompatible-pointer-types)
 # use the deterministic mode of AR if available
 KBUILD_ARFLAGS := $(call ar-option,D)
 
-# check for 'asm goto'
-ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y)
-	KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
-	KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO
-endif
-
 include scripts/Makefile.kasan
 include scripts/Makefile.extrawarn
 include scripts/Makefile.ubsan
arch/x86/entry/entry_32.S +0 -168

185 lines not on this page · raw message

arch/x86/kernel/Makefile +1 -0
index d3743a37e990..55e8902c461f 100644
@@ -47,6 +47,7 @@ obj-y			+= setup.o x86_init.o i8259.o irqinit.o jump_label.o
 obj-$(CONFIG_IRQ_WORK)  += irq_work.o
 obj-y			+= probe_roms.o
 obj-$(CONFIG_X86_64)	+= sys_x86_64.o ftrace_64.o
+obj-$(CONFIG_X86_32)	+= ftrace_32.o
 obj-$(CONFIG_X86_ESPFIX64)	+= espfix_64.o
 obj-$(CONFIG_SYSFS)	+= ksysfs.o
 obj-y			+= bootflag.o e820.o
arch/x86/kernel/ftrace_32.S new file +176 -0

176 lines not on this page · raw message

Signature · 1 line
2.10.2
author maintainer
#3 lore raw

RFC PATCH 3/5 ftrace/x86_32: Add stack frame pointer to ftrace_caller

In reply to Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

The function hook ftrace_caller does not create its own stack frame, and this causes the ftrace stack trace to miss the first function when doing stack traces.

 # echo schedule:stacktrace > /sys/kernel/tracing/set_ftrace_filter

Before:

         <idle>-0     [002] .N..    29.865807: <stack trace>
 => cpu_startup_entry
 => start_secondary
 => startup_32_smp
           <...>-7     [001] ....    29.866509: <stack trace>
 => kthread
 => ret_from_fork
           <...>-1     [000] ....    29.865377: <stack trace>

=> poll_schedule_timeout
=> do_select
=> core_sys_select
=> SyS_select
=> do_fast_syscall_32
=> entry_SYSENTER_32

After:

          <idle>-0     [002] .N..    31.234853: <stack trace>
 => do_idle
 => cpu_startup_entry
 => start_secondary
 => startup_32_smp
           <...>-7     [003] ....    31.235140: <stack trace>
 => rcu_gp_kthread
 => kthread
 => ret_from_fork
           <...>-1819  [000] ....    31.264172: <stack trace>

=> schedule_hrtimeout_range
=> poll_schedule_timeout
=> do_sys_poll
=> SyS_ppoll
=> do_fast_syscall_32
=> entry_SYSENTER_32

---
 arch/x86/kernel/ftrace_32.S | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
arch/x86/kernel/ftrace_32.S +10 -2
index 4ff30f31f0a5..73d61a62649d 100644
@@ -17,12 +17,19 @@ ENTRY(mcount)
 END(mcount)
 
 ENTRY(ftrace_caller)
+
+	pushl %ebp
+	movl %esp, %ebp
+
 	pushl	%eax
 	pushl	%ecx
 	pushl	%edx
 	pushl	$0				/* Pass NULL as regs pointer */
-	movl	4*4(%esp), %eax
-	movl	0x4(%ebp), %edx
+	movl	5*4(%esp), %eax
+	/* Copy original ebp into %edx */
+	movl	4*4(%esp), %edx
+	/* Get the parent ip */
+	movl	0x4(%edx), %edx
 	movl	function_trace_op, %ecx
 	subl	$MCOUNT_INSN_SIZE, %eax
 
@@ -34,6 +41,7 @@ ftrace_call:
 	popl	%edx
 	popl	%ecx
 	popl	%eax
+	popl	%ebp
 .Lftrace_ret:
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 .globl ftrace_graph_call
Signature · 1 line
2.10.2
Reviewed-by on v1 3/5
#4 lore raw

Re: [RFC][PATCH 3/5] ftrace/x86_32: Add stack frame pointer to ftrace_caller

Quoted 52 lines · Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

The function hook ftrace_caller does not create its own stack frame, and this causes the ftrace stack trace to miss the first function when doing stack traces.

 # echo schedule:stacktrace > /sys/kernel/tracing/set_ftrace_filter

Before:

         <idle>-0     [002] .N..    29.865807: <stack trace>
 => cpu_startup_entry
 => start_secondary
 => startup_32_smp
           <...>-7     [001] ....    29.866509: <stack trace>
 => kthread
 => ret_from_fork
           <...>-1     [000] ....    29.865377: <stack trace>

=> poll_schedule_timeout
=> do_select
=> core_sys_select
=> SyS_select
=> do_fast_syscall_32
=> entry_SYSENTER_32

After:

          <idle>-0     [002] .N..    31.234853: <stack trace>
 => do_idle
 => cpu_startup_entry
 => start_secondary
 => startup_32_smp
           <...>-7     [003] ....    31.235140: <stack trace>
 => rcu_gp_kthread
 => kthread
 => ret_from_fork
           <...>-1819  [000] ....    31.264172: <stack trace>

=> schedule_hrtimeout_range
=> poll_schedule_timeout
=> do_sys_poll
=> SyS_ppoll
=> do_fast_syscall_32
=> entry_SYSENTER_32

---
 arch/x86/kernel/ftrace_32.S | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
arch/x86/kernel/ftrace_32.S +0 -0
index 4ff30f31f0a5..73d61a62649d 100644

arch/x86/kernel/ftrace_32.S ENTRY(mcount) · line 23

Quoted 7 lines
arch/x86/kernel/ftrace_32.S +4 -0
@@ -17,12 +17,19 @@ ENTRY(mcount)
 END(mcount)
 
 ENTRY(ftrace_caller)
+
+	pushl %ebp
+	movl %esp, %ebp
+

The operands for the above two instructions should be vertically aligned like the rest of the code. Otherwise:

Signature · 1 line
Josh
author maintainer
#5 lore raw

RFC PATCH 4/5 ftrace/x86_32: Clean up ftrace_regs_caller

In reply to Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

When ftrace_regs_caller was created, it was designed to preserve flags as much as possible as it needed to act just like a breakpoint triggered on the same location. But the design is over complicated as it treated all operations as modifying flags. But push, mov and lea do not modify flags. This means the code can become more simplified by allowing flags to be stored further down.

Making ftrace_regs_caller simpler will also be useful in implementing fentry logic.

---
 arch/x86/kernel/ftrace_32.S | 45 +++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)
arch/x86/kernel/ftrace_32.S +25 -20
index 73d61a62649d..8ca33d9806ac 100644
@@ -55,23 +55,30 @@ WEAK(ftrace_stub)
 END(ftrace_caller)
 
 ENTRY(ftrace_regs_caller)
-	pushf	/* push flags before compare (in cs location) */
-
 	/*
 	 * i386 does not save SS and ESP when coming from kernel.
 	 * Instead, to get sp, &regs->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 */
+	 * regs->ip location, and move flags into the return ip location.
+         */
+	pushl	$__KERNEL_CS
+	pushl	4(%esp)				/* Save the return ip */
+
+	/* temporarily save flags in the orig_ax location */
+	pushf
 
-	pushl	$0				/* Load 0 into orig_ax */
 	pushl	%gs
 	pushl	%fs
 	pushl	%es
 	pushl	%ds
 	pushl	%eax
+
+	/* move flags into the location of where the return ip was */
+	movl	5*4(%esp), %eax
+	movl	$0, (%esp)			/* Load 0 into orig_ax */
+	movl	%eax, 8*4(%esp)
+
 	pushl	%ebp
 	pushl	%edi
 	pushl	%esi
@@ -79,11 +86,6 @@ ENTRY(ftrace_regs_caller)
 	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) */
 	subl	$MCOUNT_INSN_SIZE, %eax		/* Adjust ip */
 	movl	0x4(%ebp), %edx			/* Load parent ip (2nd parameter) */
@@ -94,10 +96,14 @@ 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 */
-	movl	%eax, 14*4(%esp)		/* Put return ip back for ret */
+
+	/* Since we don't care about cs, move flags there to simplify return */
+	movl	14*4(%esp), %eax
+	movl	%eax, 13*4(%esp)
+
+	/* Move ip back to its original location */
+	movl	12*4(%esp), %eax
+	movl	%eax, 14*4(%esp)
 
 	popl	%ebx
 	popl	%ecx
@@ -110,12 +116,11 @@ 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) */
-	jmp	.Lftrace_ret
+	addl	$8, %esp			/* Skip orig_ax and old ip */
 
-	popf
-	jmp	ftrace_stub
+	popf					/* flags is in the cs location */
+
+	jmp	.Lftrace_ret
 #else /* ! CONFIG_DYNAMIC_FTRACE */
 
 ENTRY(mcount)
Signature · 1 line
2.10.2
#6 lore raw

Re: [RFC][PATCH 4/5] ftrace/x86_32: Clean up ftrace_regs_caller

Quoted 43 lines · Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

When ftrace_regs_caller was created, it was designed to preserve flags as much as possible as it needed to act just like a breakpoint triggered on the same location. But the design is over complicated as it treated all operations as modifying flags. But push, mov and lea do not modify flags. This means the code can become more simplified by allowing flags to be stored further down.

Making ftrace_regs_caller simpler will also be useful in implementing fentry logic.

---
 arch/x86/kernel/ftrace_32.S | 45 +++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)
arch/x86/kernel/ftrace_32.S +7 -5
index 73d61a62649d..8ca33d9806ac 100644
@@ -55,23 +55,30 @@ WEAK(ftrace_stub)
 END(ftrace_caller)
 
 ENTRY(ftrace_regs_caller)
-	pushf	/* push flags before compare (in cs location) */
-
 	/*
 	 * i386 does not save SS and ESP when coming from kernel.
 	 * Instead, to get sp, &regs->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 */
+	 * regs->ip location, and move flags into the return ip location.
+         */
+	pushl	$__KERNEL_CS
+	pushl	4(%esp)				/* Save the return ip */
+
+	/* temporarily save flags in the orig_ax location */
+	pushf
 

arch/x86/kernel/ftrace_32.S WEAK(ftrace_stub) · line 79

Quoted 10 lines
arch/x86/kernel/ftrace_32.S +4 -1
-	pushl	$0				/* Load 0 into orig_ax */
 	pushl	%gs
 	pushl	%fs
 	pushl	%es
 	pushl	%ds
 	pushl	%eax
+
+	/* move flags into the location of where the return ip was */
+	movl	5*4(%esp), %eax
+	movl	$0, (%esp)			/* Load 0 into orig_ax */

This writes a 0 into regs->ax instead of regs->orig_ax.

Signature · 1 line
Josh
author maintainer
#7 lore raw

Re: [RFC][PATCH 4/5] ftrace/x86_32: Clean up ftrace_regs_caller

Quoted 44 lines · On Wed, 15 Mar 2017 16:13:43 -0500 Josh Poimboeuf <[email protected]> wrote:
Quoted 43 lines · Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

When ftrace_regs_caller was created, it was designed to preserve flags as much as possible as it needed to act just like a breakpoint triggered on the same location. But the design is over complicated as it treated all operations as modifying flags. But push, mov and lea do not modify flags. This means the code can become more simplified by allowing flags to be stored further down.

Making ftrace_regs_caller simpler will also be useful in implementing fentry logic.

---
 arch/x86/kernel/ftrace_32.S | 45 +++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)
arch/x86/kernel/ftrace_32.S +7 -5
index 73d61a62649d..8ca33d9806ac 100644
@@ -55,23 +55,30 @@ WEAK(ftrace_stub)
 END(ftrace_caller)
 
 ENTRY(ftrace_regs_caller)
-	pushf	/* push flags before compare (in cs location) */
-
 	/*
 	 * i386 does not save SS and ESP when coming from kernel.
 	 * Instead, to get sp, &regs->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 */
+	 * regs->ip location, and move flags into the return ip location.
+         */
+	pushl	$__KERNEL_CS
+	pushl	4(%esp)				/* Save the return ip */
+
+	/* temporarily save flags in the orig_ax location */
+	pushf
 
Quoted 13 lines

arch/x86/kernel/ftrace_32.S WEAK(ftrace_stub) · line 79

Quoted 10 lines
arch/x86/kernel/ftrace_32.S +4 -1
-	pushl	$0				/* Load 0 into orig_ax */
 	pushl	%gs
 	pushl	%fs
 	pushl	%es
 	pushl	%ds
 	pushl	%eax
+
+	/* move flags into the location of where the return ip was */
+	movl	5*4(%esp), %eax
+	movl	$0, (%esp)			/* Load 0 into orig_ax */  

This writes a 0 into regs->ax instead of regs->orig_ax.

Ouch, I'm surprised this didn't crash my box. Thanks for catching it.

-- Steve

maintainer Reviewed-by
#8 lore raw

Re: [RFC][PATCH 4/5] ftrace/x86_32: Clean up ftrace_regs_caller

Quoted 61 lines · On Wed, 15 Mar 2017 19:11:24 -0400 Steven Rostedt <[email protected]> wrote:
Quoted 44 lines · On Wed, 15 Mar 2017 16:13:43 -0500 Josh Poimboeuf <[email protected]> wrote:
Quoted 43 lines · Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

When ftrace_regs_caller was created, it was designed to preserve flags as much as possible as it needed to act just like a breakpoint triggered on the same location. But the design is over complicated as it treated all operations as modifying flags. But push, mov and lea do not modify flags. This means the code can become more simplified by allowing flags to be stored further down.

Making ftrace_regs_caller simpler will also be useful in implementing fentry logic.

---
 arch/x86/kernel/ftrace_32.S | 45 +++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)
arch/x86/kernel/ftrace_32.S +7 -5
index 73d61a62649d..8ca33d9806ac 100644
@@ -55,23 +55,30 @@ WEAK(ftrace_stub)
 END(ftrace_caller)
 
 ENTRY(ftrace_regs_caller)
-	pushf	/* push flags before compare (in cs location) */
-
 	/*
 	 * i386 does not save SS and ESP when coming from kernel.
 	 * Instead, to get sp, &regs->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 */
+	 * regs->ip location, and move flags into the return ip location.
+         */
+	pushl	$__KERNEL_CS
+	pushl	4(%esp)				/* Save the return ip */
+
+	/* temporarily save flags in the orig_ax location */
+	pushf
 
Quoted 13 lines

arch/x86/kernel/ftrace_32.S WEAK(ftrace_stub) · line 79

Quoted 10 lines
arch/x86/kernel/ftrace_32.S +4 -1
-	pushl	$0				/* Load 0 into orig_ax */
 	pushl	%gs
 	pushl	%fs
 	pushl	%es
 	pushl	%ds
 	pushl	%eax
+
+	/* move flags into the location of where the return ip was */
+	movl	5*4(%esp), %eax
+	movl	$0, (%esp)			/* Load 0 into orig_ax */  

This writes a 0 into regs->ax instead of regs->orig_ax.

Quoted 1 line

Ouch, I'm surprised this didn't crash my box. Thanks for catching it.

Since mcount/fentry is just "called", %eax (caller-saved register) will be ignored :) Of course for kprobes and livepatch, this should be critical.

Except for the above point, it seems good to me.

Thanks,

Signature · 1 line
Masami Hiramatsu <[email protected]>
author maintainer
#9 lore raw

RFC PATCH 5/5 ftrace/x86-32: Add -mfentry support to x86_32 with DYNAMIC_FTRACE set

In reply to Steven Rostedt

From: "Steven Rostedt (VMware)" <[email protected]>

x86_64 has had fentry support for some time. I did not add support to x86_32 as I was unsure if it will be used much in the future. It is still very much used, and there's issues with function graph tracing with gcc playing around with the mcount frames, causing function graph to panic. The fentry code does not have this issue, and is able to cope as there is no frame to mess up.

Note, this only add support for fentry when DYNAMIC_FTRACE is set. There's really no reason to not have that set, because the performance of the machine drops significantly when it's not enabled. I only keep !DYNAMIC_FTRACE around to test it off, as there's still some archs that have FTRACE but not DYNAMIC_FTRACE.

---
 arch/x86/Kconfig            |  2 +-
 arch/x86/kernel/ftrace_32.S | 88 +++++++++++++++++++++++++++++++++++++++------
 2 files changed, 79 insertions(+), 11 deletions(-)
arch/x86/Kconfig +1 -1
index cc98d5a294ee..8c17146427ca 100644
@@ -127,7 +127,7 @@ config X86
 	select HAVE_EBPF_JIT			if X86_64
 	select HAVE_EFFICIENT_UNALIGNED_ACCESS
 	select HAVE_EXIT_THREAD
-	select HAVE_FENTRY			if X86_64
+	select HAVE_FENTRY			if X86_64 || DYNAMIC_FTRACE
 	select HAVE_FTRACE_MCOUNT_RECORD
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_FUNCTION_TRACER
arch/x86/kernel/ftrace_32.S +78 -10

150 lines not on this page · raw message

Signature · 1 line
2.10.2
#10 lore raw

Re: [RFC][PATCH 5/5] ftrace/x86-32: Add -mfentry support to x86_32 with DYNAMIC_FTRACE set

Quoted 8 lines · Steven Rostedt
arch/x86/kernel/ftrace_32.S +8 -0
+#ifdef USING_FRAME_POINTER
+# ifdef CC_USING_FENTRY
+	/*
+	 * Frame pointers are of ip followed by bp.
+	 * Since fentry is an immediate jump, we are left with
+	 * parent-ip, function-ip. We need to add a frame with
+	 * parent-ip followed by ebp.
+	 */

arch/x86/kernel/ftrace_32.S line 63

Quoted 10 lines
arch/x86/kernel/ftrace_32.S +7 -1
+	pushl 4(%esp)				/* parent ip */
 	pushl %ebp
 	movl %esp, %ebp
-
+	pushl 2*4(%esp)				/* function ip */
+# endif
+	/* For mcount, the function ip is directly above */
+	pushl %ebp
+	movl %esp, %ebp
+#endif

More vertical operand alignment issues.

arch/x86/kernel/ftrace_32.S ENTRY(ftrace_regs_caller) · line 146

Quoted 8 lines
arch/x86/kernel/ftrace_32.S +4 -0
@@ -85,6 +140,10 @@ ENTRY(ftrace_regs_caller)
 	pushl	%edx
 	pushl	%ecx
 	pushl	%ebx
+#ifndef USING_FRAME_POINTER
+	/* Load 4 off of the parent ip addr into ebp */
+	lea	14*4(%esp), %ebp
+#endif

Instead of:

	#ifndef USING_FRAME_POINTER

Shouldn't it be:

	#ifdef CC_USING_FENTRY

?

Otherwise, if I'm reading it right, with fentry and CONFIG_FRAME_POINTER=y, ebp will lead to the grandparent's ip instead of the parent's ip.

Signature · 1 line
Josh
author maintainer
#11 lore raw

Re: [RFC][PATCH 5/5] ftrace/x86-32: Add -mfentry support to x86_32 with DYNAMIC_FTRACE set

Quoted 37 lines · On Wed, 15 Mar 2017 16:55:45 -0500 Josh Poimboeuf <[email protected]> wrote:
Quoted 8 lines · Steven Rostedt
arch/x86/kernel/ftrace_32.S +8 -0
+#ifdef USING_FRAME_POINTER
+# ifdef CC_USING_FENTRY
+	/*
+	 * Frame pointers are of ip followed by bp.
+	 * Since fentry is an immediate jump, we are left with
+	 * parent-ip, function-ip. We need to add a frame with
+	 * parent-ip followed by ebp.
+	 */

arch/x86/kernel/ftrace_32.S line 63

Quoted 10 lines
arch/x86/kernel/ftrace_32.S +7 -1
+	pushl 4(%esp)				/* parent ip */
 	pushl %ebp
 	movl %esp, %ebp
-
+	pushl 2*4(%esp)				/* function ip */
+# endif
+	/* For mcount, the function ip is directly above */
+	pushl %ebp
+	movl %esp, %ebp
+#endif  

More vertical operand alignment issues.

arch/x86/kernel/ftrace_32.S ENTRY(ftrace_regs_caller) · line 146

Quoted 8 lines
arch/x86/kernel/ftrace_32.S +4 -0
@@ -85,6 +140,10 @@ ENTRY(ftrace_regs_caller)
 	pushl	%edx
 	pushl	%ecx
 	pushl	%ebx
+#ifndef USING_FRAME_POINTER
+	/* Load 4 off of the parent ip addr into ebp */
+	lea	14*4(%esp), %ebp
+#endif  

Instead of:

	#ifndef USING_FRAME_POINTER

Shouldn't it be:

Quoted 7 lines
	#ifdef CC_USING_FENTRY

?

Otherwise, if I'm reading it right, with fentry and CONFIG_FRAME_POINTER=y, ebp will lead to the grandparent's ip instead of the parent's ip.

Yep I think you're right. I original added frame pointer setup for the parent on CC_USING_FENTRY and FRAME_POINTER but that got ugly, this may be leftover from that.

Thanks, will update.

-- Steve

maintainer
#12 lore raw

Re: [RFC][PATCH 5/5] ftrace/x86-32: Add -mfentry support to x86_32 with DYNAMIC_FTRACE set

In reply to Steven Rostedt
Quoted 57 lines · On Wed, 15 Mar 2017 15:55:32 -0400 Steven Rostedt <[email protected]> wrote:

From: "Steven Rostedt (VMware)" <[email protected]>

x86_64 has had fentry support for some time. I did not add support to x86_32 as I was unsure if it will be used much in the future. It is still very much used, and there's issues with function graph tracing with gcc playing around with the mcount frames, causing function graph to panic. The fentry code does not have this issue, and is able to cope as there is no frame to mess up.

Note, this only add support for fentry when DYNAMIC_FTRACE is set. There's really no reason to not have that set, because the performance of the machine drops significantly when it's not enabled. I only keep !DYNAMIC_FTRACE around to test it off, as there's still some archs that have FTRACE but not DYNAMIC_FTRACE.

---
 arch/x86/Kconfig            |  2 +-
 arch/x86/kernel/ftrace_32.S | 88 +++++++++++++++++++++++++++++++++++++++------
 2 files changed, 79 insertions(+), 11 deletions(-)
arch/x86/Kconfig +1 -1
index cc98d5a294ee..8c17146427ca 100644
@@ -127,7 +127,7 @@ config X86
 	select HAVE_EBPF_JIT			if X86_64
 	select HAVE_EFFICIENT_UNALIGNED_ACCESS
 	select HAVE_EXIT_THREAD
-	select HAVE_FENTRY			if X86_64
+	select HAVE_FENTRY			if X86_64 || DYNAMIC_FTRACE
 	select HAVE_FTRACE_MCOUNT_RECORD
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_FUNCTION_TRACER
arch/x86/kernel/ftrace_32.S +15 -0
index 8ca33d9806ac..4bf8223555cd 100644
@@ -9,27 +9,75 @@
 #include <asm/export.h>
 #include <asm/ftrace.h>
 
+
+#ifdef CC_USING_FENTRY
+# define function_hook	__fentry__
+EXPORT_SYMBOL(__fentry__)
+#else
+# define function_hook	mcount
+EXPORT_SYMBOL(mcount)
+#endif
+
+/* mcount uses a frame pointer even if CONFIG_FRAME_POINTER is not set */
+#if !defined(CC_USING_FENTRY) || defined(CONFIG_FRAME_POINTER)
+# define USING_FRAME_POINTER
+#endif
+
+#ifdef USING_FRAME_POINTER

arch/x86/kernel/ftrace_32.S line 36

Quoted 10 lines
arch/x86/kernel/ftrace_32.S +10 -0
+# ifdef CC_USING_FENTRY
+#  define MCOUNT_FRAME_SIZE		(4*4)	/* bp,ip and parent's  */
+# else
+#  define MCOUNT_FRAME_SIZE		4	/* just the bp         */
+# endif
+# define MCOUNT_FRAME			1	/* using frame = true  */
+#else
+# define MCOUNT_FRAME_SIZE		0	/* no stack frame      */
+# define MCOUNT_FRAME			0	/* using frame = false */
+#endif

It seems that there is no use of MCOUNT_FRAME_SIZE below. Do we really need it?

Thanks,

Signature · 1 line
Masami Hiramatsu <[email protected]>
author maintainer
#13 lore raw

Re: [RFC][PATCH 5/5] ftrace/x86-32: Add -mfentry support to x86_32 with DYNAMIC_FTRACE set

Quoted 10 lines · On Thu, 16 Mar 2017 18:24:12 +0900 Masami Hiramatsu <[email protected]> wrote:
Quoted 10 lines
arch/x86/kernel/ftrace_32.S +10 -0
+/* mcount uses a frame pointer even if CONFIG_FRAME_POINTER is not set */
+#if !defined(CC_USING_FENTRY) || defined(CONFIG_FRAME_POINTER)
+# define USING_FRAME_POINTER
+#endif
+
+#ifdef USING_FRAME_POINTER
+# ifdef CC_USING_FENTRY
+#  define MCOUNT_FRAME_SIZE		(4*4)	/* bp,ip and parent's  */
+# else
+#  define MCOUNT_FRAME_SIZE		4	/* just the bp         */
Quoted 8 lines

arch/x86/kernel/ftrace_32.S line 36

Quoted 6 lines
arch/x86/kernel/ftrace_32.S +6 -0
+# endif
+# define MCOUNT_FRAME			1	/* using frame = true  */
+#else
+# define MCOUNT_FRAME_SIZE		0	/* no stack frame      */
+# define MCOUNT_FRAME			0	/* using frame = false */
+#endif  

It seems that there is no use of MCOUNT_FRAME_SIZE below. Do we really need it?

Hmm, one of the previous versions of my patch required it. I think I was able to tinker with the code to remove all the use cases of it. But I never removed the definition. Thanks, I'll fix this too.

-- Steve