1
2
3
4
5
6
7
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
45
46
47
48
49
50
51
52
53
54
55
56
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 #11 @ 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