1/* 2 * linux/arch/arm/lib/backtrace.S 3 * 4 * Copyright (C) 1995, 1996 Russell King 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * 27/03/03 Ian Molton Clean up CONFIG_CPU 11 * 12 */ 13#include <linux/linkage.h> 14#include <asm/assembler.h> 15 .text 16 17@ fp is 0 or stack frame 18 19#define frame r4 20#define sv_fp r5 21#define sv_pc r6 22#define mask r7 23#define offset r8 24 25ENTRY(c_backtrace) 26 27#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) 28 mov pc, lr 29ENDPROC(c_backtrace) 30#else 31 stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... 32 movs frame, r0 @ if frame pointer is zero 33 beq no_frame @ we have no stack frames 34 35 tst r1, #0x10 @ 26 or 32-bit mode? 36 ARM( moveq mask, #0xfc000003 ) 37 THUMB( moveq mask, #0xfc000000 ) 38 THUMB( orreq mask, #0x03 ) 39 movne mask, #0 @ mask for 32-bit 40 411: stmfd sp!, {pc} @ calculate offset of PC stored 42 ldr r0, [sp], #4 @ by stmfd for this CPU 43 adr r1, 1b 44 sub offset, r0, r1 45 46/* 47 * Stack frame layout: 48 * optionally saved caller registers (r4 - r10) 49 * saved fp 50 * saved sp 51 * saved lr 52 * frame => saved pc 53 * optionally saved arguments (r0 - r3) 54 * saved sp => <next word> 55 * 56 * Functions start with the following code sequence: 57 * mov ip, sp 58 * stmfd sp!, {r0 - r3} (optional) 59 * corrected pc => stmfd sp!, {..., fp, ip, lr, pc} 60 */ 61for_each_frame: tst frame, mask @ Check for address exceptions 62 bne no_frame 63 641001: ldr sv_pc, [frame, #0] @ get saved pc 651002: ldr sv_fp, [frame, #-12] @ get saved fp 66 67 sub sv_pc, sv_pc, offset @ Correct PC for prefetching 68 bic sv_pc, sv_pc, mask @ mask PC/LR for the mode 69 701003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 71 ldr r3, .Ldsi+4 @ adjust saved 'pc' back one 72 teq r3, r2, lsr #10 @ instruction 73 subne r0, sv_pc, #4 @ allow for mov 74 subeq r0, sv_pc, #8 @ allow for mov + stmia 75 76 ldr r1, [frame, #-4] @ get saved lr 77 mov r2, frame 78 bic r1, r1, mask @ mask PC/LR for the mode 79 bl dump_backtrace_entry 80 81 ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, 82 ldr r3, .Ldsi+4 83 teq r3, r1, lsr #10 84 ldreq r0, [frame, #-8] @ get sp 85 subeq r0, r0, #4 @ point at the last arg 86 bleq .Ldumpstm @ dump saved registers 87 881004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} 89 ldr r3, .Ldsi @ instruction exists, 90 teq r3, r1, lsr #10 91 subeq r0, frame, #16 92 bleq .Ldumpstm @ dump saved registers 93 94 teq sv_fp, #0 @ zero saved fp means 95 beq no_frame @ no further frames 96 97 cmp sv_fp, frame @ next frame must be 98 mov frame, sv_fp @ above the current frame 99 bhi for_each_frame 100 1011006: adr r0, .Lbad 102 mov r1, frame 103 bl printk 104no_frame: ldmfd sp!, {r4 - r8, pc} 105ENDPROC(c_backtrace) 106 107 .pushsection __ex_table,"a" 108 .align 3 109 .long 1001b, 1006b 110 .long 1002b, 1006b 111 .long 1003b, 1006b 112 .long 1004b, 1006b 113 .popsection 114 115#define instr r4 116#define reg r5 117#define stack r6 118 119.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} 120 mov stack, r0 121 mov instr, r1 122 mov reg, #10 123 mov r7, #0 1241: mov r3, #1 125 ARM( tst instr, r3, lsl reg ) 126 THUMB( lsl r3, reg ) 127 THUMB( tst instr, r3 ) 128 beq 2f 129 add r7, r7, #1 130 teq r7, #6 131 moveq r7, #1 132 moveq r1, #'\n' 133 movne r1, #' ' 134 ldr r3, [stack], #-4 135 mov r2, reg 136 adr r0, .Lfp 137 bl printk 1382: subs reg, reg, #1 139 bpl 1b 140 teq r7, #0 141 adrne r0, .Lcr 142 blne printk 143 ldmfd sp!, {instr, reg, stack, r7, pc} 144 145.Lfp: .asciz "%cr%d:%08x" 146.Lcr: .asciz "\n" 147.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" 148 .align 149.Ldsi: .word 0xe92dd800 >> 10 @ stmfd sp!, {... fp, ip, lr, pc} 150 .word 0xe92d0000 >> 10 @ stmfd sp!, {} 151 152#endif 153