summaryrefslogtreecommitdiff
path: root/arch/unicore32/lib/backtrace.S
blob: f303671e2a4e9a7bb3a1ae6e3c690cd166cba0a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * linux/arch/unicore32/lib/backtrace.S
 *
 * Code specific to PKUnity SoC and UniCore ISA
 *
 * Copyright (C) 2001-2010 GUAN Xue-tao
 */
#include <linux/linkage.h>
#include <asm/assembler.h>
		.text

@ fp is 0 or stack frame

#define frame	v4
#define sv_fp	v5
#define sv_pc	v6
#define offset	v8

ENTRY(__backtrace)
		mov	r0, fp

ENTRY(c_backtrace)

#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
		mov	pc, lr
ENDPROC(__backtrace)
ENDPROC(c_backtrace)
#else
		stm.w	(v4 - v8, lr), [sp-]	@ Save an extra register
						@ so we have a location...
		mov.a	frame, r0		@ if frame pointer is zero
		beq	no_frame		@ we have no stack frames

1:		stm.w	(pc), [sp-]		@ calculate offset of PC stored
		ldw.w	r0, [sp]+, #4		@ by stmfd for this CPU
		adr	r1, 1b
		sub	offset, r0, r1

/*
 * Stack frame layout:
 *             optionally saved caller registers (r4 - r10)
 *             saved fp
 *             saved sp
 *             saved lr
 *    frame => saved pc
 *             optionally saved arguments (r0 - r3)
 * saved sp => <next word>
 *
 * Functions start with the following code sequence:
 *                  mov   ip, sp
 *                  stm.w (r0 - r3), [sp-] (optional)
 * corrected pc =>  stm.w sp, (..., fp, ip, lr, pc)
 */
for_each_frame:

1001:		ldw	sv_pc, [frame+], #0	@ get saved pc
1002:		ldw	sv_fp, [frame+], #-12	@ get saved fp

		sub	sv_pc, sv_pc, offset	@ Correct PC for prefetching

1003:		ldw	r2, [sv_pc+], #-4	@ if stmfd sp, {args} exists,
		ldw	r3, .Ldsi+4		@ adjust saved 'pc' back one
		cxor.a	r3, r2 >> #14		@ instruction
		beq	201f
		sub	r0, sv_pc, #4		@ allow for mov
		b	202f
201:
		sub	r0, sv_pc, #8		@ allow for mov + stmia
202:
		ldw	r1, [frame+], #-4	@ get saved lr
		mov	r2, frame
		b.l	dump_backtrace_entry

		ldw	r1, [sv_pc+], #-4	@ if stmfd sp, {args} exists,
		ldw	r3, .Ldsi+4
		cxor.a	r3, r1 >> #14
		bne	1004f
		ldw	r0, [frame+], #-8	@ get sp
		sub	r0, r0, #4		@ point at the last arg
		b.l	.Ldumpstm		@ dump saved registers

1004:		ldw	r1, [sv_pc+], #0	@ if stmfd {, fp, ip, lr, pc}
		ldw	r3, .Ldsi		@ instruction exists,
		cxor.a	r3, r1 >> #14
		bne	201f
		sub	r0, frame, #16
		b.l	.Ldumpstm		@ dump saved registers
201:
		cxor.a	sv_fp, #0		@ zero saved fp means
		beq	no_frame		@ no further frames

		csub.a	sv_fp, frame		@ next frame must be
		mov	frame, sv_fp		@ above the current frame
		bua	for_each_frame

1006:		adr	r0, .Lbad
		mov	r1, frame
		b.l	printk
no_frame:	ldm.w	(v4 - v8, pc), [sp]+
ENDPROC(__backtrace)
ENDPROC(c_backtrace)

		.pushsection __ex_table,"a"
		.align	3
		.long	1001b, 1006b
		.long	1002b, 1006b
		.long	1003b, 1006b
		.long	1004b, 1006b
		.popsection

#define instr v4
#define reg   v5
#define stack v6

.Ldumpstm:	stm.w	(instr, reg, stack, v7, lr), [sp-]
		mov	stack, r0
		mov	instr, r1
		mov	reg, #14
		mov	v7, #0
1:		mov	r3, #1
		csub.a	reg, #8
		bne	201f
		sub	reg, reg, #3
201:
		cand.a	instr, r3 << reg
		beq	2f
		add	v7, v7, #1
		cxor.a	v7, #6
		cmoveq	v7, #1
		cmoveq	r1, #'\n'
		cmovne	r1, #' '
		ldw.w	r3, [stack]+, #-4
		mov	r2, reg
		csub.a	r2, #8
		bsl	201f
		sub	r2, r2, #3
201:
		cand.a	instr, #0x40		@ if H is 1, high 16 regs
		beq	201f
		add	r2, r2, #0x10		@ so r2 need add 16
201:
		adr	r0, .Lfp
		b.l	printk
2:		sub.a	reg, reg, #1
		bns	1b
		cxor.a	v7, #0
		beq	201f
		adr	r0, .Lcr
		b.l	printk
201:		ldm.w	(instr, reg, stack, v7, pc), [sp]+

.Lfp:		.asciz	"%cr%d:%08x"
.Lcr:		.asciz	"\n"
.Lbad:		.asciz	"Backtrace aborted due to bad frame pointer <%p>\n"
		.align
.Ldsi:		.word	0x92eec000 >> 14	@ stm.w sp, (... fp, ip, lr, pc)
		.word	0x92e10000 >> 14	@ stm.w sp, ()

#endif