xref: /OK3568_Linux_fs/kernel/drivers/soc/rockchip/fiq_debugger/fiq_debugger_arm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2014 Google, Inc.
3  * Author: Colin Cross <ccross@android.com>
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 
16 #include <linux/ptrace.h>
17 #include <linux/uaccess.h>
18 
19 #include <asm/stacktrace.h>
20 
21 #include "fiq_debugger_priv.h"
22 
mode_name(unsigned cpsr)23 static char *mode_name(unsigned cpsr)
24 {
25 	switch (cpsr & MODE_MASK) {
26 	case USR_MODE: return "USR";
27 	case FIQ_MODE: return "FIQ";
28 	case IRQ_MODE: return "IRQ";
29 	case SVC_MODE: return "SVC";
30 	case ABT_MODE: return "ABT";
31 	case UND_MODE: return "UND";
32 	case SYSTEM_MODE: return "SYS";
33 	default: return "???";
34 	}
35 }
36 
fiq_debugger_dump_pc(struct fiq_debugger_output * output,const struct pt_regs * regs)37 void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
38 		const struct pt_regs *regs)
39 {
40 	output->printf(output, " pc %08x cpsr %08x mode %s\n",
41 		regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr));
42 }
43 
fiq_debugger_dump_regs(struct fiq_debugger_output * output,const struct pt_regs * regs)44 void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
45 		const struct pt_regs *regs)
46 {
47 	output->printf(output,
48 			" r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
49 			regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
50 	output->printf(output,
51 			" r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
52 			regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
53 	output->printf(output,
54 			" r8 %08x  r9 %08x r10 %08x r11 %08x  mode %s\n",
55 			regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp,
56 			mode_name(regs->ARM_cpsr));
57 	output->printf(output,
58 			" ip %08x  sp %08x  lr %08x  pc %08x cpsr %08x\n",
59 			regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc,
60 			regs->ARM_cpsr);
61 }
62 
63 struct mode_regs {
64 	unsigned long sp_svc;
65 	unsigned long lr_svc;
66 	unsigned long spsr_svc;
67 
68 	unsigned long sp_abt;
69 	unsigned long lr_abt;
70 	unsigned long spsr_abt;
71 
72 	unsigned long sp_und;
73 	unsigned long lr_und;
74 	unsigned long spsr_und;
75 
76 	unsigned long sp_irq;
77 	unsigned long lr_irq;
78 	unsigned long spsr_irq;
79 
80 	unsigned long r8_fiq;
81 	unsigned long r9_fiq;
82 	unsigned long r10_fiq;
83 	unsigned long r11_fiq;
84 	unsigned long r12_fiq;
85 	unsigned long sp_fiq;
86 	unsigned long lr_fiq;
87 	unsigned long spsr_fiq;
88 };
89 
get_mode_regs(struct mode_regs * regs)90 static void __naked get_mode_regs(struct mode_regs *regs)
91 {
92 	asm volatile (
93 	"mrs	r1, cpsr\n"
94 #ifdef CONFIG_THUMB2_KERNEL
95 	"mov	r3, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
96 	"msr	cpsr_c, r3\n"
97 	"str	r13, [r0], 4\n"
98 	"str	r14, [r0], 4\n"
99 	"mrs	r2, spsr\n"
100 	"mov	r3, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
101 	"msr	cpsr_c, r3\n"
102 	"str	r2, [r0], 4\n"
103 	"str	r13, [r0], 4\n"
104 	"str	r14, [r0], 4\n"
105 	"mrs	r2, spsr\n"
106 	"mov	r3, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
107 	"msr	cpsr_c, r3\n"
108 	"str	r2, [r0], 4\n"
109 	"str	r13, [r0], 4\n"
110 	"str	r14, [r0], 4\n"
111 	"mrs	r2, spsr\n"
112 	"mov	r3, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
113 	"msr	cpsr_c, r3\n"
114 	"str	r2, [r0], 4\n"
115 	"str	r13, [r0], 4\n"
116 	"str	r14, [r0], 4\n"
117 	"mrs	r2, spsr\n"
118 	"mov	r3, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
119 	"msr	cpsr_c, r3\n"
120 	"stmia	r0!, {r2, r8 - r12}\n"
121 	"str	r13, [r0], 4\n"
122 	"str	r14, [r0], 4\n"
123 #else
124 	"msr	cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
125 	"stmia	r0!, {r13 - r14}\n"
126 	"mrs	r2, spsr\n"
127 	"msr	cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
128 	"stmia	r0!, {r2, r13 - r14}\n"
129 	"mrs	r2, spsr\n"
130 	"msr	cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
131 	"stmia	r0!, {r2, r13 - r14}\n"
132 	"mrs	r2, spsr\n"
133 	"msr	cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
134 	"stmia	r0!, {r2, r13 - r14}\n"
135 	"mrs	r2, spsr\n"
136 	"msr	cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
137 	"stmia	r0!, {r2, r8 - r14}\n"
138 #endif
139 	"mrs	r2, spsr\n"
140 	"stmia	r0!, {r2}\n"
141 	"msr	cpsr_c, r1\n"
142 	"bx	lr\n");
143 }
144 
145 
fiq_debugger_dump_allregs(struct fiq_debugger_output * output,const struct pt_regs * regs)146 void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
147 		const struct pt_regs *regs)
148 {
149 	struct mode_regs mode_regs;
150 	unsigned long mode = regs->ARM_cpsr & MODE_MASK;
151 
152 	fiq_debugger_dump_regs(output, regs);
153 	get_mode_regs(&mode_regs);
154 
155 	output->printf(output,
156 			"%csvc: sp %08x  lr %08x  spsr %08x\n",
157 			mode == SVC_MODE ? '*' : ' ',
158 			mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
159 	output->printf(output,
160 			"%cabt: sp %08x  lr %08x  spsr %08x\n",
161 			mode == ABT_MODE ? '*' : ' ',
162 			mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
163 	output->printf(output,
164 			"%cund: sp %08x  lr %08x  spsr %08x\n",
165 			mode == UND_MODE ? '*' : ' ',
166 			mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
167 	output->printf(output,
168 			"%cirq: sp %08x  lr %08x  spsr %08x\n",
169 			mode == IRQ_MODE ? '*' : ' ',
170 			mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
171 	output->printf(output,
172 			"%cfiq: r8 %08x  r9 %08x  r10 %08x  r11 %08x  r12 %08x\n",
173 			mode == FIQ_MODE ? '*' : ' ',
174 			mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
175 			mode_regs.r11_fiq, mode_regs.r12_fiq);
176 	output->printf(output,
177 			" fiq: sp %08x  lr %08x  spsr %08x\n",
178 			mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
179 }
180 
181 struct stacktrace_state {
182 	struct fiq_debugger_output *output;
183 	unsigned int depth;
184 };
185 
report_trace(struct stackframe * frame,void * d)186 static int report_trace(struct stackframe *frame, void *d)
187 {
188 	struct stacktrace_state *sts = d;
189 
190 	if (sts->depth) {
191 		sts->output->printf(sts->output,
192 			"  pc: %px (%pS), lr %px (%pS), sp %px, fp %px\n",
193 			frame->pc, frame->pc, frame->lr, frame->lr,
194 			frame->sp, frame->fp);
195 		sts->depth--;
196 		return 0;
197 	}
198 	sts->output->printf(sts->output, "  ...\n");
199 
200 	return sts->depth == 0;
201 }
202 
203 #ifndef CONFIG_FIQ_DEBUGGER_MODULE
204 struct frame_tail {
205 	struct frame_tail *fp;
206 	unsigned long sp;
207 	unsigned long lr;
208 } __attribute__((packed));
209 
user_backtrace(struct fiq_debugger_output * output,struct frame_tail * tail)210 static struct frame_tail *user_backtrace(struct fiq_debugger_output *output,
211 					struct frame_tail *tail)
212 {
213 	struct frame_tail buftail[2];
214 
215 	/* Also check accessibility of one struct frame_tail beyond */
216 	if (!access_ok(tail, sizeof(buftail))) {
217 		output->printf(output, "  invalid frame pointer %px\n",
218 				tail);
219 		return NULL;
220 	}
221 	if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
222 		output->printf(output,
223 			"  failed to copy frame pointer %px\n", tail);
224 		return NULL;
225 	}
226 
227 	output->printf(output, "  %px\n", buftail[0].lr);
228 
229 	/* frame pointers should strictly progress back up the stack
230 	 * (towards higher addresses) */
231 	if (tail >= buftail[0].fp)
232 		return NULL;
233 
234 	return buftail[0].fp-1;
235 }
236 
fiq_debugger_dump_stacktrace(struct fiq_debugger_output * output,const struct pt_regs * regs,unsigned int depth,void * ssp)237 void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
238 		const struct pt_regs *regs, unsigned int depth, void *ssp)
239 {
240 	struct frame_tail *tail;
241 	struct thread_info *real_thread_info = THREAD_INFO(ssp);
242 	struct stacktrace_state sts;
243 
244 	sts.depth = depth;
245 	sts.output = output;
246 	*current_thread_info() = *real_thread_info;
247 
248 	if (!current)
249 		output->printf(output, "current NULL\n");
250 	else
251 		output->printf(output, "pid: %d  comm: %s\n",
252 			current->pid, current->comm);
253 	fiq_debugger_dump_regs(output, regs);
254 
255 	if (!user_mode(regs)) {
256 		struct stackframe frame;
257 		frame.fp = regs->ARM_fp;
258 		frame.sp = regs->ARM_sp;
259 		frame.lr = regs->ARM_lr;
260 		frame.pc = regs->ARM_pc;
261 		output->printf(output, "\n");
262 		walk_stackframe(&frame, report_trace, &sts);
263 		return;
264 	}
265 
266 	tail = ((struct frame_tail *) regs->ARM_fp) - 1;
267 	while (depth-- && tail && !((unsigned long) tail & 3))
268 		tail = user_backtrace(output, tail);
269 }
270 #endif
271