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