Merge tag 'gpio-v5.3-rc7-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kerne...
[sfrench/cifs-2.6.git] / arch / arm / lib / backtrace.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  *  linux/arch/arm/lib/backtrace.S
4  *
5  *  Copyright (C) 1995, 1996 Russell King
6  *
7  * 27/03/03 Ian Molton Clean up CONFIG_CPU
8  */
9 #include <linux/kern_levels.h>
10 #include <linux/linkage.h>
11 #include <asm/assembler.h>
12                 .text
13
14 @ fp is 0 or stack frame
15
16 #define frame   r4
17 #define sv_fp   r5
18 #define sv_pc   r6
19 #define mask    r7
20 #define offset  r8
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                 stmfd   sp!, {r4 - r8, lr}      @ Save an extra register so we have a location...
29                 movs    frame, r0               @ if frame pointer is zero
30                 beq     no_frame                @ we have no stack frames
31
32                 tst     r1, #0x10               @ 26 or 32-bit mode?
33  ARM(           moveq   mask, #0xfc000003       )
34  THUMB(         moveq   mask, #0xfc000000       )
35  THUMB(         orreq   mask, #0x03             )
36                 movne   mask, #0                @ mask for 32-bit
37
38 1:              stmfd   sp!, {pc}               @ calculate offset of PC stored
39                 ldr     r0, [sp], #4            @ by stmfd for this CPU
40                 adr     r1, 1b
41                 sub     offset, r0, r1
42
43 /*
44  * Stack frame layout:
45  *             optionally saved caller registers (r4 - r10)
46  *             saved fp
47  *             saved sp
48  *             saved lr
49  *    frame => saved pc
50  *             optionally saved arguments (r0 - r3)
51  * saved sp => <next word>
52  *
53  * Functions start with the following code sequence:
54  *                  mov   ip, sp
55  *                  stmfd sp!, {r0 - r3} (optional)
56  * corrected pc =>  stmfd sp!, {..., fp, ip, lr, pc}
57  */
58 for_each_frame: tst     frame, mask             @ Check for address exceptions
59                 bne     no_frame
60
61 1001:           ldr     sv_pc, [frame, #0]      @ get saved pc
62 1002:           ldr     sv_fp, [frame, #-12]    @ get saved fp
63
64                 sub     sv_pc, sv_pc, offset    @ Correct PC for prefetching
65                 bic     sv_pc, sv_pc, mask      @ mask PC/LR for the mode
66
67 1003:           ldr     r2, [sv_pc, #-4]        @ if stmfd sp!, {args} exists,
68                 ldr     r3, .Ldsi+4             @ adjust saved 'pc' back one
69                 teq     r3, r2, lsr #10         @ instruction
70                 subne   r0, sv_pc, #4           @ allow for mov
71                 subeq   r0, sv_pc, #8           @ allow for mov + stmia
72
73                 ldr     r1, [frame, #-4]        @ get saved lr
74                 mov     r2, frame
75                 bic     r1, r1, mask            @ mask PC/LR for the mode
76                 bl      dump_backtrace_entry
77
78                 ldr     r1, [sv_pc, #-4]        @ if stmfd sp!, {args} exists,
79                 ldr     r3, .Ldsi+4
80                 teq     r3, r1, lsr #11
81                 ldreq   r0, [frame, #-8]        @ get sp
82                 subeq   r0, r0, #4              @ point at the last arg
83                 bleq    dump_backtrace_stm      @ dump saved registers
84
85 1004:           ldr     r1, [sv_pc, #0]         @ if stmfd sp!, {..., fp, ip, lr, pc}
86                 ldr     r3, .Ldsi               @ instruction exists,
87                 teq     r3, r1, lsr #11
88                 subeq   r0, frame, #16
89                 bleq    dump_backtrace_stm      @ dump saved registers
90
91                 teq     sv_fp, #0               @ zero saved fp means
92                 beq     no_frame                @ no further frames
93
94                 cmp     sv_fp, frame            @ next frame must be
95                 mov     frame, sv_fp            @ above the current frame
96                 bhi     for_each_frame
97
98 1006:           adr     r0, .Lbad
99                 mov     r1, frame
100                 bl      printk
101 no_frame:       ldmfd   sp!, {r4 - r8, pc}
102 ENDPROC(c_backtrace)
103                 
104                 .pushsection __ex_table,"a"
105                 .align  3
106                 .long   1001b, 1006b
107                 .long   1002b, 1006b
108                 .long   1003b, 1006b
109                 .long   1004b, 1006b
110                 .popsection
111
112 .Lbad:          .asciz  "Backtrace aborted due to bad frame pointer <%p>\n"
113                 .align
114 .Ldsi:          .word   0xe92dd800 >> 11        @ stmfd sp!, {... fp, ip, lr, pc}
115                 .word   0xe92d0000 >> 11        @ stmfd sp!, {}
116
117 #endif