[RFC PATCH 1/2] ARM: deprecate old APCS frame format
Jean-Philippe Brucker
jean-philippe.brucker at arm.com
Mon Jan 25 09:05:20 PST 2016
GCC 5 deprecated option -mapcs-frame, which generated frames following
the old ABI format. In preparation for a possible removal in future
versions of GCC, deprecate use of this flag in Linux as well.
Instead of completely removing the bits that depend on APCS frame, we
move them behind a DEPRECATED config option to smoothen the transition.
Neither AAPCS nor EABI guarantees any frame format, so only ARM_UNWIND
should now be used for stack traces and introspection. It is already
selected by most defconfigs.
Furthermore, frames currently generated by GCC are different for leaf
and non-leaf functions, which would make adaptation quite tricky.
Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker at arm.com>
---
arch/arm/Kconfig.debug | 16 ++++++++++++----
arch/arm/Makefile | 6 +++++-
arch/arm/include/asm/ftrace.h | 8 ++++----
arch/arm/kernel/entry-ftrace.S | 2 +-
arch/arm/kernel/return_address.c | 4 ++--
arch/arm/kernel/stacktrace.c | 13 ++++++++++---
arch/arm/lib/backtrace.S | 2 +-
arch/arm/net/bpf_jit_32.c | 6 +++---
8 files changed, 38 insertions(+), 19 deletions(-)
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 259c0ca..95b85ee 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -39,9 +39,17 @@ config FRAME_POINTER
default y if !ARM_UNWIND || FUNCTION_GRAPH_TRACER
help
If you say N here, the resulting kernel will be slightly smaller and
- faster. However, if neither FRAME_POINTER nor ARM_UNWIND are enabled,
- when a problem occurs with the kernel, the information that is
- reported is severely limited.
+ faster. When ARM_UNWIND is disabled, enabling FRAME_POINTER alone is
+ not sufficient to get meaningful information in case of a kernel bug;
+ you will also need DEPRECATED_APCS_FRAME.
+
+config DEPRECATED_APCS_FRAME
+ bool "Enable deprecated frame format"
+ depends on FRAME_POINTER
+ default n
+ help
+ Use the legacy APCS frame format. This is required for ftrace with
+ GCC < 4.4, as well as stack traces without ARM_UNWIND.
config ARM_UNWIND
bool "Enable stack unwinding support (EXPERIMENTAL)"
@@ -56,7 +64,7 @@ config ARM_UNWIND
config OLD_MCOUNT
bool
- depends on FUNCTION_TRACER && FRAME_POINTER
+ depends on FUNCTION_TRACER && DEPRECATED_APCS_FRAME
default y
config DEBUG_USER
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2c2b28e..66a3adc 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -41,7 +41,11 @@ KBUILD_CFLAGS += $(call cc-option,-mno-unaligned-access)
endif
ifeq ($(CONFIG_FRAME_POINTER),y)
-KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog
+KBUILD_CFLAGS +=-fno-omit-frame-pointer -mno-sched-prolog
+endif
+
+ifeq ($(CONFIG_DEPRECATED_APCS_FRAME),y)
+KBUILD_CFLAGS +=-mapcs
endif
ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h
index bfe2a2f..a1ad19e 100644
--- a/arch/arm/include/asm/ftrace.h
+++ b/arch/arm/include/asm/ftrace.h
@@ -32,12 +32,12 @@ extern void ftrace_call_old(void);
#ifndef __ASSEMBLY__
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+#if defined(CONFIG_DEPRECATED_APCS_FRAME) && !defined(CONFIG_ARM_UNWIND)
/*
* return_address uses walk_stackframe to do it's work. If both
- * CONFIG_FRAME_POINTER=y and CONFIG_ARM_UNWIND=y walk_stackframe uses unwind
- * information. For this to work in the function tracer many functions would
- * have to be marked with __notrace. So for now just depend on
+ * CONFIG_DEPRECATED_APCS_FRAME=y and CONFIG_ARM_UNWIND=y walk_stackframe uses
+ * unwind information. For this to work in the function tracer many functions
+ * would have to be marked with __notrace. So for now just depend on
* !CONFIG_ARM_UNWIND.
*/
diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S
index c73c403..b9984b5 100644
--- a/arch/arm/kernel/entry-ftrace.S
+++ b/arch/arm/kernel/entry-ftrace.S
@@ -53,7 +53,7 @@
#ifndef CONFIG_OLD_MCOUNT
#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
-#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0.
+#error Ftrace requires CONFIG_DEPRECATED_APCS_FRAME=y with GCC older than 4.4.0.
#endif
#endif
diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c
index 36ed350..3728026 100644
--- a/arch/arm/kernel/return_address.c
+++ b/arch/arm/kernel/return_address.c
@@ -11,7 +11,7 @@
#include <linux/export.h>
#include <linux/ftrace.h>
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+#if defined(CONFIG_DEPRECATED_APCS_FRAME) && !defined(CONFIG_ARM_UNWIND)
#include <linux/sched.h>
#include <asm/stacktrace.h>
@@ -56,6 +56,6 @@ void *return_address(unsigned int level)
return NULL;
}
-#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
+#endif /* if defined(CONFIG_DEPRECATED_APCS_FRAME) && !defined(CONFIG_ARM_UNWIND) */
EXPORT_SYMBOL_GPL(return_address);
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index 92b7237..20e9a7f 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -5,13 +5,14 @@
#include <asm/stacktrace.h>
#include <asm/traps.h>
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+#ifndef CONFIG_ARM_UNWIND
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
/*
* Unwind the current stack frame and store the new register values in the
* structure passed as argument. Unwinding is equivalent to a function return,
* hence the new PC value rather than LR should be used for backtrace.
*
- * With framepointer enabled, a simple function prologue looks like this:
+ * With APCS frames enabled, a simple function prologue looks like this:
* mov ip, sp
* stmdb sp!, {fp, ip, lr, pc}
* sub fp, ip, #4
@@ -19,7 +20,7 @@
* A simple function epilogue looks like this:
* ldm sp, {fp, sp, pc}
*
- * Note that with framepointer enabled, even the leaf functions have the same
+ * Note that with APCS frames enabled, even the leaf functions have the same
* prologue and epilogue, therefore we can ignore the LR value in this case.
*/
int notrace unwind_frame(struct stackframe *frame)
@@ -42,7 +43,13 @@ int notrace unwind_frame(struct stackframe *frame)
return 0;
}
+#else /* !defined(CONFIG_DEPRECATED_APCS_FRAME) */
+int notrace unwind_frame(struct stackframe *frame)
+{
+ return -EINVAL;
+}
#endif
+#endif /* !defined(CONFIG_ARM_UNWIND) */
void notrace walk_stackframe(struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data)
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index fab5a50..3041ccb 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -24,7 +24,7 @@
ENTRY(c_backtrace)
-#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
+#if !defined(CONFIG_DEPRECATED_APCS_FRAME) || !defined(CONFIG_PRINTK)
ret lr
ENDPROC(c_backtrace)
#else
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 93d0b6d..8f7b718 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -165,7 +165,7 @@ static u16 saved_regs(struct jit_ctx *ctx)
(ctx->skf->insns[0].code == (BPF_RET | BPF_A)))
ret |= 1 << r_A;
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
ret |= (1 << ARM_FP) | (1 << ARM_IP) | (1 << ARM_LR) | (1 << ARM_PC);
#else
if (ctx->seen & SEEN_CALL)
@@ -200,7 +200,7 @@ static void build_prologue(struct jit_ctx *ctx)
u16 reg_set = saved_regs(ctx);
u16 off;
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx);
emit(ARM_PUSH(reg_set), ctx);
emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx);
@@ -244,7 +244,7 @@ static void build_epilogue(struct jit_ctx *ctx)
reg_set &= ~(1 << ARM_LR);
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DEPRECATED_APCS_FRAME
/* the first instruction of the prologue was: mov ip, sp */
reg_set &= ~(1 << ARM_IP);
reg_set |= (1 << ARM_SP);
--
1.7.9.5
More information about the linux-arm-kernel
mailing list