.text
@ fp is 0 or stack frame
ENTRY(c_backtrace)
ret lr
ENDPROC(c_backtrace)
stmfd sp!, {r4 - r9, lr} @ Save an extra register so we have a location...
movs frame, r0 @ if frame pointer is zero
beq no_frame @ we have no stack frames
mov loglvl, r2
tst r1,
ARM( moveq mask,
THUMB( moveq mask,
THUMB( orreq mask,
movne mask,
1: stmfd sp!, {pc} @ calculate offset of PC stored
ldr r0, [sp],
adr r1, 1b
sub offset, r0, r1
for_each_frame: tst frame, mask @ Check for address exceptions
bne no_frame
1001: ldr sv_pc, [frame,
1002: ldr sv_fp, [frame,
sub sv_pc, sv_pc, offset @ Correct PC for prefetching
bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
1003: ldr r2, [sv_pc,
ldr r3, .Ldsi+4 @ adjust saved 'pc' back one
teq r3, r2, lsr
subne r0, sv_pc,
subeq r0, sv_pc,
ldr r1, [frame,
mov r2, frame
bic r1, r1, mask @ mask PC/LR for the mode
mov r3, loglvl
bl dump_backtrace_entry
ldr r1, [sv_pc,
ldr r3, .Ldsi+4
teq r3, r1, lsr
ldreq r0, [frame,
subeq r0, r0,
mov r2, loglvl
bleq dump_backtrace_stm @ dump saved registers
1004: ldr r1, [sv_pc,
ldr r3, .Ldsi @ instruction exists,
teq r3, r1, lsr
subeq r0, frame,
mov r2, loglvl
bleq dump_backtrace_stm @ dump saved registers
teq sv_fp,
beq no_frame @ no further frames
cmp sv_fp, frame @ next frame must be
mov frame, sv_fp @ above the current frame
@
@ Kernel stacks may be discontiguous in memory. If the next
@ frame is below the previous frame, accept it as long as it
@ lives in kernel memory.
@
cmpls sv_fp,
bhi for_each_frame
1006: adr r0, .Lbad
mov r1, loglvl
mov r2, frame
bl _printk
no_frame: ldmfd sp!, {r4 - r9, pc}
ENDPROC(c_backtrace)
.pushsection __ex_table,"a"
.align 3
.long 1001b, 1006b
.long 1002b, 1006b
.long 1003b, 1006b
.long 1004b, 1006b
.popsection
.Lbad: .asciz "%sBacktrace aborted due to bad frame pointer <%p>\n"
.align
.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc}
.word 0xe92d0000 >> 11 @ stmfd sp!, {}