summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Huckleberry <nhuck15@gmail.com>2019-08-22 16:26:53 -0400
committerRussell King <rmk+kernel@armlinux.org.uk>2019-08-29 02:58:01 -0400
commit6dc5fd93b2f1ef75d5e50fced8cb193811f25f22 (patch)
treeaef0050d64248b77af6b90a9601146739227180b
parent834020366da9ab3fb87d1eb9a3160eb22dbed63a (diff)
ARM: 8900/1: UNWINDER_FRAME_POINTER implementation for Clang
The stackframe setup when compiled with clang is different. Since the stack unwinder expects the gcc stackframe setup it fails to print backtraces. This patch adds support for the clang stackframe setup. Link: https://github.com/ClangBuiltLinux/linux/issues/35 Cc: clang-built-linux@googlegroups.com Suggested-by: Tri Vo <trong@google.com> Signed-off-by: Nathan Huckleberry <nhuck@google.com> Tested-by: Nick Desaulniers <ndesaulniers@google.com> Reviewed-by: Nick Desaulniers <ndesaulniers@google.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--arch/arm/Kconfig.debug2
-rw-r--r--arch/arm/Makefile5
-rw-r--r--arch/arm/lib/Makefile8
-rw-r--r--arch/arm/lib/backtrace-clang.S217
4 files changed, 229 insertions, 3 deletions
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 85710e078afb..b9c674ec19e0 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -56,7 +56,7 @@ choice
56 56
57config UNWINDER_FRAME_POINTER 57config UNWINDER_FRAME_POINTER
58 bool "Frame pointer unwinder" 58 bool "Frame pointer unwinder"
59 depends on !THUMB2_KERNEL && !CC_IS_CLANG 59 depends on !THUMB2_KERNEL
60 select ARCH_WANT_FRAME_POINTERS 60 select ARCH_WANT_FRAME_POINTERS
61 select FRAME_POINTER 61 select FRAME_POINTER
62 help 62 help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 288fa2a6dbea..977f4e66f145 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -36,7 +36,10 @@ KBUILD_CFLAGS += $(call cc-option,-mno-unaligned-access)
36endif 36endif
37 37
38ifeq ($(CONFIG_FRAME_POINTER),y) 38ifeq ($(CONFIG_FRAME_POINTER),y)
39KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog 39KBUILD_CFLAGS +=-fno-omit-frame-pointer
40ifeq ($(CONFIG_CC_IS_GCC),y)
41KBUILD_CFLAGS += -mapcs -mno-sched-prolog
42endif
40endif 43endif
41 44
42ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) 45ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index b25c54585048..6d2ba454f25b 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -5,7 +5,7 @@
5# Copyright (C) 1995-2000 Russell King 5# Copyright (C) 1995-2000 Russell King
6# 6#
7 7
8lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ 8lib-y := changebit.o csumipv6.o csumpartial.o \
9 csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ 9 csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
10 delay.o delay-loop.o findbit.o memchr.o memcpy.o \ 10 delay.o delay-loop.o findbit.o memchr.o memcpy.o \
11 memmove.o memset.o setbit.o \ 11 memmove.o memset.o setbit.o \
@@ -19,6 +19,12 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
19mmu-y := clear_user.o copy_page.o getuser.o putuser.o \ 19mmu-y := clear_user.o copy_page.o getuser.o putuser.o \
20 copy_from_user.o copy_to_user.o 20 copy_from_user.o copy_to_user.o
21 21
22ifdef CONFIG_CC_IS_CLANG
23 lib-y += backtrace-clang.o
24else
25 lib-y += backtrace.o
26endif
27
22# using lib_ here won't override already available weak symbols 28# using lib_ here won't override already available weak symbols
23obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o 29obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
24 30
diff --git a/arch/arm/lib/backtrace-clang.S b/arch/arm/lib/backtrace-clang.S
new file mode 100644
index 000000000000..2ff375144b55
--- /dev/null
+++ b/arch/arm/lib/backtrace-clang.S
@@ -0,0 +1,217 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * linux/arch/arm/lib/backtrace-clang.S
4 *
5 * Copyright (C) 2019 Nathan Huckleberry
6 *
7 */
8#include <linux/kern_levels.h>
9#include <linux/linkage.h>
10#include <asm/assembler.h>
11 .text
12
13/* fp is 0 or stack frame */
14
15#define frame r4
16#define sv_fp r5
17#define sv_pc r6
18#define mask r7
19#define sv_lr r8
20
21ENTRY(c_backtrace)
22
23#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
24 ret lr
25ENDPROC(c_backtrace)
26#else
27
28
29/*
30 * Clang does not store pc or sp in function prologues so we don't know exactly
31 * where the function starts.
32 *
33 * We can treat the current frame's lr as the saved pc and the preceding
34 * frame's lr as the current frame's lr, but we can't trace the most recent
35 * call. Inserting a false stack frame allows us to reference the function
36 * called last in the stacktrace.
37 *
38 * If the call instruction was a bl we can look at the callers branch
39 * instruction to calculate the saved pc. We can recover the pc in most cases,
40 * but in cases such as calling function pointers we cannot. In this case,
41 * default to using the lr. This will be some address in the function, but will
42 * not be the function start.
43 *
44 * Unfortunately due to the stack frame layout we can't dump r0 - r3, but these
45 * are less frequently saved.
46 *
47 * Stack frame layout:
48 * <larger addresses>
49 * saved lr
50 * frame=> saved fp
51 * optionally saved caller registers (r4 - r10)
52 * optionally saved arguments (r0 - r3)
53 * <top of stack frame>
54 * <smaller addresses>
55 *
56 * Functions start with the following code sequence:
57 * corrected pc => stmfd sp!, {..., fp, lr}
58 * add fp, sp, #x
59 * stmfd sp!, {r0 - r3} (optional)
60 *
61 *
62 *
63 *
64 *
65 *
66 * The diagram below shows an example stack setup for dump_stack.
67 *
68 * The frame for c_backtrace has pointers to the code of dump_stack. This is
69 * why the frame of c_backtrace is used to for the pc calculation of
70 * dump_stack. This is why we must move back a frame to print dump_stack.
71 *
72 * The stored locals for dump_stack are in dump_stack's frame. This means that
73 * to fully print dump_stack's frame we need both the frame for dump_stack (for
74 * locals) and the frame that was called by dump_stack (for pc).
75 *
76 * To print locals we must know where the function start is. If we read the
77 * function prologue opcodes we can determine which variables are stored in the
78 * stack frame.
79 *
80 * To find the function start of dump_stack we can look at the stored LR of
81 * show_stack. It points at the instruction directly after the bl dump_stack.
82 * We can then read the offset from the bl opcode to determine where the branch
83 * takes us. The address calculated must be the start of dump_stack.
84 *
85 * c_backtrace frame dump_stack:
86 * {[LR] } ============| ...
87 * {[FP] } =======| | bl c_backtrace
88 * | |=> ...
89 * {[R4-R10]} |
90 * {[R0-R3] } | show_stack:
91 * dump_stack frame | ...
92 * {[LR] } =============| bl dump_stack
93 * {[FP] } <=======| |=> ...
94 * {[R4-R10]}
95 * {[R0-R3] }
96 */
97
98 stmfd sp!, {r4 - r9, fp, lr} @ Save an extra register
99 @ to ensure 8 byte alignment
100 movs frame, r0 @ if frame pointer is zero
101 beq no_frame @ we have no stack frames
102 tst r1, #0x10 @ 26 or 32-bit mode?
103 moveq mask, #0xfc000003
104 movne mask, #0 @ mask for 32-bit
105
106/*
107 * Switches the current frame to be the frame for dump_stack.
108 */
109 add frame, sp, #24 @ switch to false frame
110for_each_frame: tst frame, mask @ Check for address exceptions
111 bne no_frame
112
113/*
114 * sv_fp is the stack frame with the locals for the current considered
115 * function.
116 *
117 * sv_pc is the saved lr frame the frame above. This is a pointer to a code
118 * address within the current considered function, but it is not the function
119 * start. This value gets updated to be the function start later if it is
120 * possible.
121 */
1221001: ldr sv_pc, [frame, #4] @ get saved 'pc'
1231002: ldr sv_fp, [frame, #0] @ get saved fp
124
125 teq sv_fp, mask @ make sure next frame exists
126 beq no_frame
127
128/*
129 * sv_lr is the lr from the function that called the current function. This is
130 * a pointer to a code address in the current function's caller. sv_lr-4 is
131 * the instruction used to call the current function.
132 *
133 * This sv_lr can be used to calculate the function start if the function was
134 * called using a bl instruction. If the function start can be recovered sv_pc
135 * is overwritten with the function start.
136 *
137 * If the current function was called using a function pointer we cannot
138 * recover the function start and instead continue with sv_pc as an arbitrary
139 * value within the current function. If this is the case we cannot print
140 * registers for the current function, but the stacktrace is still printed
141 * properly.
142 */
1431003: ldr sv_lr, [sv_fp, #4] @ get saved lr from next frame
144
145 ldr r0, [sv_lr, #-4] @ get call instruction
146 ldr r3, .Lopcode+4
147 and r2, r3, r0 @ is this a bl call
148 teq r2, r3
149 bne finished_setup @ give up if it's not
150 and r0, #0xffffff @ get call offset 24-bit int
151 lsl r0, r0, #8 @ sign extend offset
152 asr r0, r0, #8
153 ldr sv_pc, [sv_fp, #4] @ get lr address
154 add sv_pc, sv_pc, #-4 @ get call instruction address
155 add sv_pc, sv_pc, #8 @ take care of prefetch
156 add sv_pc, sv_pc, r0, lsl #2@ find function start
157
158finished_setup:
159
160 bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
161
162/*
163 * Print the function (sv_pc) and where it was called from (sv_lr).
164 */
1651004: mov r0, sv_pc
166
167 mov r1, sv_lr
168 mov r2, frame
169 bic r1, r1, mask @ mask PC/LR for the mode
170 bl dump_backtrace_entry
171
172/*
173 * Test if the function start is a stmfd instruction to determine which
174 * registers were stored in the function prologue.
175 *
176 * If we could not recover the sv_pc because we were called through a function
177 * pointer the comparison will fail and no registers will print. Unwinding will
178 * continue as if there had been no registers stored in this frame.
179 */
1801005: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, lr}
181 ldr r3, .Lopcode @ instruction exists,
182 teq r3, r1, lsr #11
183 ldr r0, [frame] @ locals are stored in
184 @ the preceding frame
185 subeq r0, r0, #4
186 bleq dump_backtrace_stm @ dump saved registers
187
188/*
189 * If we are out of frames or if the next frame is invalid.
190 */
191 teq sv_fp, #0 @ zero saved fp means
192 beq no_frame @ no further frames
193
194 cmp sv_fp, frame @ next frame must be
195 mov frame, sv_fp @ above the current frame
196 bhi for_each_frame
197
1981006: adr r0, .Lbad
199 mov r1, frame
200 bl printk
201no_frame: ldmfd sp!, {r4 - r9, fp, pc}
202ENDPROC(c_backtrace)
203 .pushsection __ex_table,"a"
204 .align 3
205 .long 1001b, 1006b
206 .long 1002b, 1006b
207 .long 1003b, 1006b
208 .long 1004b, 1006b
209 .long 1005b, 1006b
210 .popsection
211
212.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"
213 .align
214.Lopcode: .word 0xe92d4800 >> 11 @ stmfd sp!, {... fp, lr}
215 .word 0x0b000000 @ bl if these bits are set
216
217#endif