aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/lib
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2007-03-02 10:01:36 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-04-21 15:34:34 -0400
commit7ab3f8d595a1b1e5cf8d726b72fd476fe0d0226c (patch)
treed37cf7290d5df5927ff870bfbb40673bead8f00d /arch/arm/lib
parent46fcc86dd71d70211e965102fb69414c90381880 (diff)
[ARM] Add ability to dump exception stacks to kernel backtraces
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/lib')
-rw-r--r--arch/arm/lib/backtrace.S165
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
421: moveq r0, #-2 41
43 ldmeqfd sp!, {r4 - r8, pc} 421: stmfd sp!, {pc} @ calculate offset of PC stored
44 43 ldr r0, [sp], #4 @ by stmfd for this CPU
452: 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
503: 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 */
62for_each_frame: tst frame, mask @ Check for address exceptions
63 bne no_frame
64
651001: ldr sv_pc, [frame, #0] @ get saved pc
661002: ldr sv_fp, [frame, #-12] @ get saved fp
52 67
531001: ldr next, [frame, #-12] @ get fp 68 sub sv_pc, sv_pc, offset @ Correct PC for prefetching
541002: ldr r2, [frame, #-4] @ get lr 69 bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
551003: ldr r3, [frame, #0] @ get pc 70
56 sub save, r3, offset @ Correct PC for prefetching 711003: 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
581004: 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
691005: 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
771006: 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/* 891004: 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
1011007: 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
1021006: adr r0, .Lbad
102 mov r1, frame 103 mov r1, frame
103 bl printk 104 bl printk
104 ldmfd sp!, {r4 - r8, pc} 105no_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
1261: mov r3, #1 1241: 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
1382: subs reg, reg, #1 1362: 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