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#include <linux/config.h>
11#include <linux/linkage.h>
12#include <asm/assembler.h>
13		.text
14
15@ fp is 0 or stack frame
16
17#define frame	r4
18#define next	r5
19#define save	r6
20#define mask	r7
21#define offset	r8
22
23ENTRY(__backtrace)
24		mov	r1, #0x10
25		mov	r0, fp
26
27ENTRY(c_backtrace)
28
29#ifndef CONFIG_FRAME_POINTER
30		mov	pc, lr
31#else
32
33		stmfd	sp!, {r4 - r8, lr}	@ Save an extra register so we have a location...
34#ifdef CONFIG_CPU_32
35		tst	r1, #0x10		@ 26 or 32-bit?
36		moveq	mask, #0xfc000003
37		movne	mask, #0
38#else
39		mov	mask, #0xfc000003
40#endif
41		tst	mask, r0
42		movne	r0, #0
43		movs	frame, r0
441:		moveq	r0, #-2
45		LOADREGS(eqfd, sp!, {r4 - r8, pc})
46
472:		stmfd	sp!, {pc}		@ calculate offset of PC in STMIA instruction
48		ldr	r0, [sp], #4
49		adr	r1, 2b - 4
50		sub	offset, r0, r1
51
523:		tst	frame, mask		@ Check for address exceptions...
53		bne	1b
54
551001:		ldmda	frame, {r0, r1, r2, r3}	@ fp, sp, lr, pc
56		mov	next, r0
57
58		sub	save, r3, offset	@ Correct PC for prefetching
59		bic	save, save, mask
60		adr	r0, .Lfe
61		mov	r1, save
62		bic	r2, r2, mask
63		bl	SYMBOL_NAME(printk)	@ print pc and link register
64
65		sub	r0, frame, #16
661002:		ldr	r1, [save, #4]		@ get instruction at function+4
67		mov	r3, r1, lsr #10
68		ldr	r2, .Ldsi+4
69		teq	r3, r2			@ Check for stmia sp!, {args}
70		addeq	save, save, #4		@ next instruction
71		bleq	.Ldumpstm
72
731003:		ldr	r1, [save, #4]		@ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction
74		mov	r3, r1, lsr #10
75		ldr	r2, .Ldsi
76		teq	r3, r2
77		bleq	.Ldumpstm
78
79		teq	frame, next
80		movne	frame, next
81		teqne	frame, #0
82		bne	3b
83		LOADREGS(fd, sp!, {r4 - r8, pc})
84
85/*
86 * Fixup for LDMDB
87 */
88		.section .fixup,"ax"
89		.align	0
901004:		ldr	r0, =.Lbad
91		mov	r1, frame
92		bl	SYMBOL_NAME(printk)
93		LOADREGS(fd, sp!, {r4 - r8, pc})
94		.ltorg
95		.previous
96
97		.section __ex_table,"a"
98		.align	3
99		.long	1001b, 1004b
100		.long	1002b, 1004b
101		.long	1003b, 1004b
102		.previous
103
104#define instr r4
105#define reg   r5
106#define stack r6
107
108.Ldumpstm:	stmfd	sp!, {instr, reg, stack, r7, lr}
109		mov	stack, r0
110		mov	instr, r1
111		mov	reg, #9
112		mov	r7, #0
1131:		mov	r3, #1
114		tst	instr, r3, lsl reg
115		beq	2f
116		add	r7, r7, #1
117		teq	r7, #4
118		moveq	r7, #0
119		moveq	r3, #'\n'
120		movne	r3, #' '
121		ldr	r2, [stack], #-4
122		mov	r1, reg
123		adr	r0, .Lfp
124		bl	SYMBOL_NAME(printk)
1252:		subs	reg, reg, #1
126		bpl	1b
127		teq	r7, #0
128		adrne	r0, .Lcr
129		blne	SYMBOL_NAME(printk)
130		mov	r0, stack
131		LOADREGS(fd, sp!, {instr, reg, stack, r7, pc})
132
133.Lfe:		.asciz	"Function entered at [<%p>] from [<%p>]\n"
134.Lfp:		.asciz	" r%d = %08X%c"
135.Lcr:		.asciz	"\n"
136.Lbad:		.asciz	"Backtrace aborted due to bad frame pointer <%p>\n"
137		.align
138.Ldsi:		.word	0x00e92dd8 >> 2
139		.word	0x00e92d00 >> 2
140
141#endif
142