diff options
Diffstat (limited to 'arch/arm/lib/backtrace.S')
-rw-r--r-- | arch/arm/lib/backtrace.S | 165 |
1 files changed, 81 insertions, 84 deletions
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S index 74230083cbf4..84dc890d2bf3 100644 --- a/arch/arm/lib/backtrace.S +++ b/arch/arm/lib/backtrace.S | |||
@@ -17,8 +17,8 @@ | |||
17 | @ fp is 0 or stack frame | 17 | @ fp is 0 or stack frame |
18 | 18 | ||
19 | #define frame r4 | 19 | #define frame r4 |
20 | #define next r5 | 20 | #define sv_fp r5 |
21 | #define save r6 | 21 | #define sv_pc r6 |
22 | #define mask r7 | 22 | #define mask r7 |
23 | #define offset r8 | 23 | #define offset r8 |
24 | 24 | ||
@@ -31,108 +31,106 @@ ENTRY(c_backtrace) | |||
31 | #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) | 31 | #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) |
32 | mov pc, lr | 32 | mov pc, lr |
33 | #else | 33 | #else |
34 | |||
35 | stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... | 34 | stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... |
36 | tst r1, #0x10 @ 26 or 32-bit? | 35 | movs frame, r0 @ if frame pointer is zero |
37 | moveq mask, #0xfc000003 | 36 | beq no_frame @ we have no stack frames |
38 | movne mask, #0 | 37 | |
39 | tst mask, r0 | 38 | tst r1, #0x10 @ 26 or 32-bit mode? |
40 | movne r0, #0 | 39 | moveq mask, #0xfc000003 @ mask for 26-bit |
41 | movs frame, r0 | 40 | movne mask, #0 @ mask for 32-bit |
42 | 1: moveq r0, #-2 | 41 | |
43 | ldmeqfd sp!, {r4 - r8, pc} | 42 | 1: stmfd sp!, {pc} @ calculate offset of PC stored |
44 | 43 | ldr r0, [sp], #4 @ by stmfd for this CPU | |
45 | 2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction | 44 | adr r1, 1b |
46 | ldr r0, [sp], #4 | ||
47 | adr r1, 2b - 4 | ||
48 | sub offset, r0, r1 | 45 | sub offset, r0, r1 |
49 | 46 | ||
50 | 3: tst frame, mask @ Check for address exceptions... | 47 | /* |
51 | bne 1b | 48 | * Stack frame layout: |
49 | * optionally saved caller registers (r4 - r10) | ||
50 | * saved fp | ||
51 | * saved sp | ||
52 | * saved lr | ||
53 | * frame => saved pc | ||
54 | * optionally saved arguments (r0 - r3) | ||
55 | * saved sp => <next word> | ||
56 | * | ||
57 | * Functions start with the following code sequence: | ||
58 | * mov ip, sp | ||
59 | * stmfd sp!, {r0 - r3} (optional) | ||
60 | * corrected pc => stmfd sp!, {..., fp, ip, lr, pc} | ||
61 | */ | ||
62 | for_each_frame: tst frame, mask @ Check for address exceptions | ||
63 | bne no_frame | ||
64 | |||
65 | 1001: ldr sv_pc, [frame, #0] @ get saved pc | ||
66 | 1002: ldr sv_fp, [frame, #-12] @ get saved fp | ||
52 | 67 | ||
53 | 1001: ldr next, [frame, #-12] @ get fp | 68 | sub sv_pc, sv_pc, offset @ Correct PC for prefetching |
54 | 1002: ldr r2, [frame, #-4] @ get lr | 69 | bic sv_pc, sv_pc, mask @ mask PC/LR for the mode |
55 | 1003: ldr r3, [frame, #0] @ get pc | 70 | |
56 | sub save, r3, offset @ Correct PC for prefetching | 71 | 1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists, |
57 | bic save, save, mask | 72 | ldr r3, .Ldsi+4 @ adjust saved 'pc' back one |
58 | 1004: ldr r1, [save, #0] @ get instruction at function | 73 | teq r3, r2, lsr #10 @ instruction |
59 | mov r1, r1, lsr #10 | 74 | subne r0, sv_pc, #4 @ allow for mov |
60 | ldr r3, .Ldsi+4 | 75 | subeq r0, sv_pc, #8 @ allow for mov + stmia |
61 | teq r1, r3 | 76 | |
62 | subeq save, save, #4 | 77 | ldr r1, [frame, #-4] @ get saved lr |
63 | mov r0, save | 78 | mov r2, frame |
64 | bic r1, r2, mask | 79 | bic r1, r1, mask @ mask PC/LR for the mode |
65 | bl dump_backtrace_entry | 80 | bl dump_backtrace_entry |
66 | 81 | ||
67 | ldr r0, [frame, #-8] @ get sp | 82 | ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, |
68 | sub r0, r0, #4 | 83 | ldr r3, .Ldsi+4 |
69 | 1005: ldr r1, [save, #4] @ get instruction at function+4 | 84 | teq r3, r1, lsr #10 |
70 | mov r3, r1, lsr #10 | 85 | ldreq r0, [frame, #-8] @ get sp |
71 | ldr r2, .Ldsi+4 | 86 | subeq r0, r0, #4 @ point at the last arg |
72 | teq r3, r2 @ Check for stmia sp!, {args} | 87 | bleq .Ldumpstm @ dump saved registers |
73 | addeq save, save, #4 @ next instruction | ||
74 | bleq .Ldumpstm | ||
75 | |||
76 | sub r0, frame, #16 | ||
77 | 1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction | ||
78 | mov r3, r1, lsr #10 | ||
79 | ldr r2, .Ldsi | ||
80 | teq r3, r2 | ||
81 | bleq .Ldumpstm | ||
82 | |||
83 | /* | ||
84 | * A zero next framepointer means we're done. | ||
85 | */ | ||
86 | teq next, #0 | ||
87 | ldmeqfd sp!, {r4 - r8, pc} | ||
88 | |||
89 | /* | ||
90 | * The next framepointer must be above the | ||
91 | * current framepointer. | ||
92 | */ | ||
93 | cmp next, frame | ||
94 | mov frame, next | ||
95 | bhi 3b | ||
96 | b 1007f | ||
97 | 88 | ||
98 | /* | 89 | 1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} |
99 | * Fixup for LDMDB. Note that this must not be in the fixup section. | 90 | ldr r3, .Ldsi @ instruction exists, |
100 | */ | 91 | teq r3, r1, lsr #10 |
101 | 1007: ldr r0, =.Lbad | 92 | subeq r0, frame, #16 |
93 | bleq .Ldumpstm @ dump saved registers | ||
94 | |||
95 | teq sv_fp, #0 @ zero saved fp means | ||
96 | beq no_frame @ no further frames | ||
97 | |||
98 | cmp sv_fp, frame @ next frame must be | ||
99 | mov frame, sv_fp @ above the current frame | ||
100 | bhi for_each_frame | ||
101 | |||
102 | 1006: adr r0, .Lbad | ||
102 | mov r1, frame | 103 | mov r1, frame |
103 | bl printk | 104 | bl printk |
104 | ldmfd sp!, {r4 - r8, pc} | 105 | no_frame: ldmfd sp!, {r4 - r8, pc} |
105 | .ltorg | ||
106 | 106 | ||
107 | .section __ex_table,"a" | 107 | .section __ex_table,"a" |
108 | .align 3 | 108 | .align 3 |
109 | .long 1001b, 1007b | 109 | .long 1001b, 1006b |
110 | .long 1002b, 1007b | 110 | .long 1002b, 1006b |
111 | .long 1003b, 1007b | 111 | .long 1003b, 1006b |
112 | .long 1004b, 1007b | 112 | .long 1004b, 1006b |
113 | .long 1005b, 1007b | ||
114 | .long 1006b, 1007b | ||
115 | .previous | 113 | .previous |
116 | 114 | ||
117 | #define instr r4 | 115 | #define instr r4 |
118 | #define reg r5 | 116 | #define reg r5 |
119 | #define stack r6 | 117 | #define stack r6 |
120 | 118 | ||
121 | .Ldumpstm: stmfd sp!, {instr, reg, stack, r7, r8, lr} | 119 | .Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} |
122 | mov stack, r0 | 120 | mov stack, r0 |
123 | mov instr, r1 | 121 | mov instr, r1 |
124 | mov reg, #9 | 122 | mov reg, #10 |
125 | mov r7, #0 | 123 | mov r7, #0 |
126 | 1: mov r3, #1 | 124 | 1: mov r3, #1 |
127 | tst instr, r3, lsl reg | 125 | tst instr, r3, lsl reg |
128 | beq 2f | 126 | beq 2f |
129 | add r7, r7, #1 | 127 | add r7, r7, #1 |
130 | teq r7, #4 | 128 | teq r7, #6 |
131 | moveq r7, #0 | 129 | moveq r7, #1 |
132 | moveq r3, #'\n' | 130 | moveq r1, #'\n' |
133 | movne r3, #' ' | 131 | movne r1, #' ' |
134 | ldr r2, [stack], #-4 | 132 | ldr r3, [stack], #-4 |
135 | mov r1, reg | 133 | mov r2, reg |
136 | adr r0, .Lfp | 134 | adr r0, .Lfp |
137 | bl printk | 135 | bl printk |
138 | 2: subs reg, reg, #1 | 136 | 2: subs reg, reg, #1 |
@@ -140,14 +138,13 @@ ENTRY(c_backtrace) | |||
140 | teq r7, #0 | 138 | teq r7, #0 |
141 | adrne r0, .Lcr | 139 | adrne r0, .Lcr |
142 | blne printk | 140 | blne printk |
143 | mov r0, stack | 141 | ldmfd sp!, {instr, reg, stack, r7, pc} |
144 | ldmfd sp!, {instr, reg, stack, r7, r8, pc} | ||
145 | 142 | ||
146 | .Lfp: .asciz " r%d = %08X%c" | 143 | .Lfp: .asciz "%cr%d:%08x" |
147 | .Lcr: .asciz "\n" | 144 | .Lcr: .asciz "\n" |
148 | .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" | 145 | .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" |
149 | .align | 146 | .align |
150 | .Ldsi: .word 0x00e92dd8 >> 2 | 147 | .Ldsi: .word 0xe92dd800 >> 10 @ stmfd sp!, {... fp, ip, lr, pc} |
151 | .word 0x00e92d00 >> 2 | 148 | .word 0xe92d0000 >> 10 @ stmfd sp!, {} |
152 | 149 | ||
153 | #endif | 150 | #endif |