blob: 8b3e0137be1a0b419cd017ad3a27627fe2dfa6a2 [file] [log] [blame]
Colin Crosscffbe782014-04-02 18:42:13 -07001/*
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
23static 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
Arve Hjønnevåge073df62014-05-02 19:52:54 -070037void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
Colin Crosscffbe782014-04-02 18:42:13 -070038 const struct pt_regs *regs)
39{
Arve Hjønnevåge073df62014-05-02 19:52:54 -070040 output->printf(output, " pc %08x cpsr %08x mode %s\n",
Colin Crosscffbe782014-04-02 18:42:13 -070041 regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr));
42}
43
Arve Hjønnevåge073df62014-05-02 19:52:54 -070044void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
Colin Crosscffbe782014-04-02 18:42:13 -070045 const struct pt_regs *regs)
46{
Arve Hjønnevåge073df62014-05-02 19:52:54 -070047 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -070048 " r0 %08x r1 %08x r2 %08x r3 %08x\n",
49 regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070050 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -070051 " r4 %08x r5 %08x r6 %08x r7 %08x\n",
52 regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070053 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -070054 " 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));
Arve Hjønnevåge073df62014-05-02 19:52:54 -070057 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -070058 " 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
63struct 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
90static void __naked get_mode_regs(struct mode_regs *regs)
91{
92 asm volatile (
93 "mrs r1, cpsr\n"
94 "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
95 "stmia r0!, {r13 - r14}\n"
96 "mrs r2, spsr\n"
97 "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
98 "stmia r0!, {r2, r13 - r14}\n"
99 "mrs r2, spsr\n"
100 "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
101 "stmia r0!, {r2, r13 - r14}\n"
102 "mrs r2, spsr\n"
103 "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
104 "stmia r0!, {r2, r13 - r14}\n"
105 "mrs r2, spsr\n"
106 "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
107 "stmia r0!, {r2, r8 - r14}\n"
108 "mrs r2, spsr\n"
109 "stmia r0!, {r2}\n"
110 "msr cpsr_c, r1\n"
111 "bx lr\n");
112}
113
114
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700115void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
Colin Crosscffbe782014-04-02 18:42:13 -0700116 const struct pt_regs *regs)
117{
118 struct mode_regs mode_regs;
119 unsigned long mode = regs->ARM_cpsr & MODE_MASK;
120
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700121 fiq_debugger_dump_regs(output, regs);
Colin Crosscffbe782014-04-02 18:42:13 -0700122 get_mode_regs(&mode_regs);
123
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700124 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700125 "%csvc: sp %08x lr %08x spsr %08x\n",
126 mode == SVC_MODE ? '*' : ' ',
127 mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700128 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700129 "%cabt: sp %08x lr %08x spsr %08x\n",
130 mode == ABT_MODE ? '*' : ' ',
131 mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700132 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700133 "%cund: sp %08x lr %08x spsr %08x\n",
134 mode == UND_MODE ? '*' : ' ',
135 mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700136 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700137 "%cirq: sp %08x lr %08x spsr %08x\n",
138 mode == IRQ_MODE ? '*' : ' ',
139 mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700140 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700141 "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n",
142 mode == FIQ_MODE ? '*' : ' ',
143 mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
144 mode_regs.r11_fiq, mode_regs.r12_fiq);
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700145 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700146 " fiq: sp %08x lr %08x spsr %08x\n",
147 mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
148}
149
150struct stacktrace_state {
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700151 struct fiq_debugger_output *output;
Colin Crosscffbe782014-04-02 18:42:13 -0700152 unsigned int depth;
153};
154
155static int report_trace(struct stackframe *frame, void *d)
156{
157 struct stacktrace_state *sts = d;
158
159 if (sts->depth) {
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700160 sts->output->printf(sts->output,
Colin Crosscffbe782014-04-02 18:42:13 -0700161 " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
162 frame->pc, frame->pc, frame->lr, frame->lr,
163 frame->sp, frame->fp);
164 sts->depth--;
165 return 0;
166 }
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700167 sts->output->printf(sts->output, " ...\n");
Colin Crosscffbe782014-04-02 18:42:13 -0700168
169 return sts->depth == 0;
170}
171
172struct frame_tail {
173 struct frame_tail *fp;
174 unsigned long sp;
175 unsigned long lr;
176} __attribute__((packed));
177
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700178static struct frame_tail *user_backtrace(struct fiq_debugger_output *output,
Colin Crosscffbe782014-04-02 18:42:13 -0700179 struct frame_tail *tail)
180{
181 struct frame_tail buftail[2];
182
183 /* Also check accessibility of one struct frame_tail beyond */
184 if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) {
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700185 output->printf(output, " invalid frame pointer %p\n",
Colin Crosscffbe782014-04-02 18:42:13 -0700186 tail);
187 return NULL;
188 }
189 if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700190 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700191 " failed to copy frame pointer %p\n", tail);
192 return NULL;
193 }
194
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700195 output->printf(output, " %p\n", buftail[0].lr);
Colin Crosscffbe782014-04-02 18:42:13 -0700196
197 /* frame pointers should strictly progress back up the stack
198 * (towards higher addresses) */
199 if (tail >= buftail[0].fp)
200 return NULL;
201
202 return buftail[0].fp-1;
203}
204
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700205void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
Colin Crosscffbe782014-04-02 18:42:13 -0700206 const struct pt_regs *regs, unsigned int depth, void *ssp)
207{
208 struct frame_tail *tail;
209 struct thread_info *real_thread_info = THREAD_INFO(ssp);
210 struct stacktrace_state sts;
211
212 sts.depth = depth;
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700213 sts.output = output;
Colin Crosscffbe782014-04-02 18:42:13 -0700214 *current_thread_info() = *real_thread_info;
215
216 if (!current)
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700217 output->printf(output, "current NULL\n");
Colin Crosscffbe782014-04-02 18:42:13 -0700218 else
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700219 output->printf(output, "pid: %d comm: %s\n",
Colin Crosscffbe782014-04-02 18:42:13 -0700220 current->pid, current->comm);
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700221 fiq_debugger_dump_regs(output, regs);
Colin Crosscffbe782014-04-02 18:42:13 -0700222
223 if (!user_mode(regs)) {
224 struct stackframe frame;
225 frame.fp = regs->ARM_fp;
226 frame.sp = regs->ARM_sp;
227 frame.lr = regs->ARM_lr;
228 frame.pc = regs->ARM_pc;
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700229 output->printf(output,
Colin Crosscffbe782014-04-02 18:42:13 -0700230 " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
231 regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr,
232 regs->ARM_sp, regs->ARM_fp);
233 walk_stackframe(&frame, report_trace, &sts);
234 return;
235 }
236
237 tail = ((struct frame_tail *) regs->ARM_fp) - 1;
238 while (depth-- && tail && !((unsigned long) tail & 3))
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700239 tail = user_backtrace(output, tail);
Colin Crosscffbe782014-04-02 18:42:13 -0700240}