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 | #define loglvl r9 |
21 | |
22 | ENTRY(c_backtrace) |
23 | |
24 | #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) |
25 | ret lr |
26 | ENDPROC(c_backtrace) |
27 | #else |
28 | |
29 | |
30 | /* |
31 | * Clang does not store pc or sp in function prologues so we don't know exactly |
32 | * where the function starts. |
33 | * |
34 | * We can treat the current frame's lr as the saved pc and the preceding |
35 | * frame's lr as the current frame's lr, but we can't trace the most recent |
36 | * call. Inserting a false stack frame allows us to reference the function |
37 | * called last in the stacktrace. |
38 | * |
39 | * If the call instruction was a bl we can look at the callers branch |
40 | * instruction to calculate the saved pc. We can recover the pc in most cases, |
41 | * but in cases such as calling function pointers we cannot. In this case, |
42 | * default to using the lr. This will be some address in the function, but will |
43 | * not be the function start. |
44 | * |
45 | * Unfortunately due to the stack frame layout we can't dump r0 - r3, but these |
46 | * are less frequently saved. |
47 | * |
48 | * Stack frame layout: |
49 | * <larger addresses> |
50 | * saved lr |
51 | * frame=> saved fp |
52 | * optionally saved caller registers (r4 - r10) |
53 | * optionally saved arguments (r0 - r3) |
54 | * <top of stack frame> |
55 | * <smaller addresses> |
56 | * |
57 | * Functions start with the following code sequence: |
58 | * corrected pc => stmfd sp!, {..., fp, lr} |
59 | * add fp, sp, #x |
60 | * stmfd sp!, {r0 - r3} (optional) |
61 | * |
62 | * |
63 | * |
64 | * |
65 | * |
66 | * |
67 | * The diagram below shows an example stack setup for dump_stack. |
68 | * |
69 | * The frame for c_backtrace has pointers to the code of dump_stack. This is |
70 | * why the frame of c_backtrace is used to for the pc calculation of |
71 | * dump_stack. This is why we must move back a frame to print dump_stack. |
72 | * |
73 | * The stored locals for dump_stack are in dump_stack's frame. This means that |
74 | * to fully print dump_stack's frame we need both the frame for dump_stack (for |
75 | * locals) and the frame that was called by dump_stack (for pc). |
76 | * |
77 | * To print locals we must know where the function start is. If we read the |
78 | * function prologue opcodes we can determine which variables are stored in the |
79 | * stack frame. |
80 | * |
81 | * To find the function start of dump_stack we can look at the stored LR of |
82 | * show_stack. It points at the instruction directly after the bl dump_stack. |
83 | * We can then read the offset from the bl opcode to determine where the branch |
84 | * takes us. The address calculated must be the start of dump_stack. |
85 | * |
86 | * c_backtrace frame dump_stack: |
87 | * {[LR] } ============| ... |
88 | * {[FP] } =======| | bl c_backtrace |
89 | * | |=> ... |
90 | * {[R4-R10]} | |
91 | * {[R0-R3] } | show_stack: |
92 | * dump_stack frame | ... |
93 | * {[LR] } =============| bl dump_stack |
94 | * {[FP] } <=======| |=> ... |
95 | * {[R4-R10]} |
96 | * {[R0-R3] } |
97 | */ |
98 | |
99 | stmfd sp!, {r4 - r9, fp, lr} @ Save an extra register |
100 | @ to ensure 8 byte alignment |
101 | movs frame, r0 @ if frame pointer is zero |
102 | beq no_frame @ we have no stack frames |
103 | mov loglvl, r2 |
104 | tst r1, #0x10 @ 26 or 32-bit mode? |
105 | moveq mask, #0xfc000003 |
106 | movne mask, #0 @ mask for 32-bit |
107 | |
108 | /* |
109 | * Switches the current frame to be the frame for dump_stack. |
110 | */ |
111 | add frame, sp, #24 @ switch to false frame |
112 | for_each_frame: tst frame, mask @ Check for address exceptions |
113 | bne no_frame |
114 | |
115 | /* |
116 | * sv_fp is the stack frame with the locals for the current considered |
117 | * function. |
118 | * |
119 | * sv_pc is the saved lr frame the frame above. This is a pointer to a code |
120 | * address within the current considered function, but it is not the function |
121 | * start. This value gets updated to be the function start later if it is |
122 | * possible. |
123 | */ |
124 | 1001: ldr sv_pc, [frame, #4] @ get saved 'pc' |
125 | 1002: ldr sv_fp, [frame, #0] @ get saved fp |
126 | |
127 | teq sv_fp, mask @ make sure next frame exists |
128 | beq no_frame |
129 | |
130 | /* |
131 | * sv_lr is the lr from the function that called the current function. This is |
132 | * a pointer to a code address in the current function's caller. sv_lr-4 is |
133 | * the instruction used to call the current function. |
134 | * |
135 | * This sv_lr can be used to calculate the function start if the function was |
136 | * called using a bl instruction. If the function start can be recovered sv_pc |
137 | * is overwritten with the function start. |
138 | * |
139 | * If the current function was called using a function pointer we cannot |
140 | * recover the function start and instead continue with sv_pc as an arbitrary |
141 | * value within the current function. If this is the case we cannot print |
142 | * registers for the current function, but the stacktrace is still printed |
143 | * properly. |
144 | */ |
145 | 1003: ldr sv_lr, [sv_fp, #4] @ get saved lr from next frame |
146 | |
147 | 1004: ldr r0, [sv_lr, #-4] @ get call instruction |
148 | ldr r3, .Lopcode+4 |
149 | and r2, r3, r0 @ is this a bl call |
150 | teq r2, r3 |
151 | bne finished_setup @ give up if it's not |
152 | and r0, #0xffffff @ get call offset 24-bit int |
153 | lsl r0, r0, #8 @ sign extend offset |
154 | asr r0, r0, #8 |
155 | ldr sv_pc, [sv_fp, #4] @ get lr address |
156 | add sv_pc, sv_pc, #-4 @ get call instruction address |
157 | add sv_pc, sv_pc, #8 @ take care of prefetch |
158 | add sv_pc, sv_pc, r0, lsl #2@ find function start |
159 | |
160 | finished_setup: |
161 | |
162 | bic sv_pc, sv_pc, mask @ mask PC/LR for the mode |
163 | |
164 | /* |
165 | * Print the function (sv_pc) and where it was called from (sv_lr). |
166 | */ |
167 | mov r0, sv_pc |
168 | |
169 | mov r1, sv_lr |
170 | mov r2, frame |
171 | bic r1, r1, mask @ mask PC/LR for the mode |
172 | mov r3, loglvl |
173 | bl dump_backtrace_entry |
174 | |
175 | /* |
176 | * Test if the function start is a stmfd instruction to determine which |
177 | * registers were stored in the function prologue. |
178 | * |
179 | * If we could not recover the sv_pc because we were called through a function |
180 | * pointer the comparison will fail and no registers will print. Unwinding will |
181 | * continue as if there had been no registers stored in this frame. |
182 | */ |
183 | 1005: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, lr} |
184 | ldr r3, .Lopcode @ instruction exists, |
185 | teq r3, r1, lsr #11 |
186 | ldr r0, [frame] @ locals are stored in |
187 | @ the preceding frame |
188 | subeq r0, r0, #4 |
189 | mov r2, loglvl |
190 | bleq dump_backtrace_stm @ dump saved registers |
191 | |
192 | /* |
193 | * If we are out of frames or if the next frame is invalid. |
194 | */ |
195 | teq sv_fp, #0 @ zero saved fp means |
196 | beq no_frame @ no further frames |
197 | |
198 | cmp sv_fp, frame @ next frame must be |
199 | mov frame, sv_fp @ above the current frame |
200 | #ifdef CONFIG_IRQSTACKS |
201 | @ |
202 | @ Kernel stacks may be discontiguous in memory. If the next |
203 | @ frame is below the previous frame, accept it as long as it |
204 | @ lives in kernel memory. |
205 | @ |
206 | cmpls sv_fp, #PAGE_OFFSET |
207 | #endif |
208 | bhi for_each_frame |
209 | |
210 | 1006: adr r0, .Lbad |
211 | mov r1, loglvl |
212 | mov r2, frame |
213 | bl _printk |
214 | no_frame: ldmfd sp!, {r4 - r9, fp, pc} |
215 | ENDPROC(c_backtrace) |
216 | .pushsection __ex_table,"a" |
217 | .align 3 |
218 | .long 1001b, 1006b |
219 | .long 1002b, 1006b |
220 | .long 1003b, 1006b |
221 | .long 1004b, finished_setup |
222 | .long 1005b, 1006b |
223 | .popsection |
224 | |
225 | .Lbad: .asciz "%sBacktrace aborted due to bad frame pointer <%p>\n" |
226 | .align |
227 | .Lopcode: .word 0xe92d4800 >> 11 @ stmfd sp!, {... fp, lr} |
228 | .word 0x0b000000 @ bl if these bits are set |
229 | |
230 | #endif |
231 | |