99c6584fcfa58f6dfe3c62ca54f714f520e10053
[firefly-linux-kernel-4.4.55.git] / drivers / staging / android / fiq_debugger / fiq_debugger_arm64.c
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 <asm/stacktrace.h>
18
19 #include "fiq_debugger_priv.h"
20
21 static char *mode_name(const struct pt_regs *regs)
22 {
23         if (compat_user_mode(regs)) {
24                 return "USR";
25         } else {
26                 switch (processor_mode(regs)) {
27                 case PSR_MODE_EL0t: return "EL0t";
28                 case PSR_MODE_EL1t: return "EL1t";
29                 case PSR_MODE_EL1h: return "EL1h";
30                 case PSR_MODE_EL2t: return "EL2t";
31                 case PSR_MODE_EL2h: return "EL2h";
32                 default: return "???";
33                 }
34         }
35 }
36
37 void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
38                 const struct pt_regs *regs)
39 {
40         output->printf(output, " pc %016lx cpsr %08lx mode %s\n",
41                 regs->pc, regs->pstate, mode_name(regs));
42 }
43
44 void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output,
45                 const struct pt_regs *regs)
46 {
47         output->printf(output, " r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
48                         regs->compat_usr(0), regs->compat_usr(1),
49                         regs->compat_usr(2), regs->compat_usr(3));
50         output->printf(output, " r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
51                         regs->compat_usr(4), regs->compat_usr(5),
52                         regs->compat_usr(6), regs->compat_usr(7));
53         output->printf(output, " r8 %08x  r9 %08x r10 %08x r11 %08x\n",
54                         regs->compat_usr(8), regs->compat_usr(9),
55                         regs->compat_usr(10), regs->compat_usr(11));
56         output->printf(output, " ip %08x  sp %08x  lr %08x  pc %08x\n",
57                         regs->compat_usr(12), regs->compat_sp,
58                         regs->compat_lr, regs->pc);
59         output->printf(output, " cpsr %08x (%s)\n",
60                         regs->pstate, mode_name(regs));
61 }
62
63 void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output,
64                 const struct pt_regs *regs)
65 {
66
67         output->printf(output, "  x0 %016lx   x1 %016lx\n",
68                         regs->regs[0], regs->regs[1]);
69         output->printf(output, "  x2 %016lx   x3 %016lx\n",
70                         regs->regs[2], regs->regs[3]);
71         output->printf(output, "  x4 %016lx   x5 %016lx\n",
72                         regs->regs[4], regs->regs[5]);
73         output->printf(output, "  x6 %016lx   x7 %016lx\n",
74                         regs->regs[6], regs->regs[7]);
75         output->printf(output, "  x8 %016lx   x9 %016lx\n",
76                         regs->regs[8], regs->regs[9]);
77         output->printf(output, " x10 %016lx  x11 %016lx\n",
78                         regs->regs[10], regs->regs[11]);
79         output->printf(output, " x12 %016lx  x13 %016lx\n",
80                         regs->regs[12], regs->regs[13]);
81         output->printf(output, " x14 %016lx  x15 %016lx\n",
82                         regs->regs[14], regs->regs[15]);
83         output->printf(output, " x16 %016lx  x17 %016lx\n",
84                         regs->regs[16], regs->regs[17]);
85         output->printf(output, " x18 %016lx  x19 %016lx\n",
86                         regs->regs[18], regs->regs[19]);
87         output->printf(output, " x20 %016lx  x21 %016lx\n",
88                         regs->regs[20], regs->regs[21]);
89         output->printf(output, " x22 %016lx  x23 %016lx\n",
90                         regs->regs[22], regs->regs[23]);
91         output->printf(output, " x24 %016lx  x25 %016lx\n",
92                         regs->regs[24], regs->regs[25]);
93         output->printf(output, " x26 %016lx  x27 %016lx\n",
94                         regs->regs[26], regs->regs[27]);
95         output->printf(output, " x28 %016lx  x29 %016lx\n",
96                         regs->regs[28], regs->regs[29]);
97         output->printf(output, " x30 %016lx   sp %016lx\n",
98                         regs->regs[30], regs->sp);
99         output->printf(output, "  pc %016lx cpsr %08x (%s)\n",
100                         regs->pc, regs->pstate, mode_name(regs));
101 }
102
103 void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
104                 const struct pt_regs *regs)
105 {
106         if (compat_user_mode(regs))
107                 fiq_debugger_dump_regs_aarch32(output, regs);
108         else
109                 fiq_debugger_dump_regs_aarch64(output, regs);
110 }
111
112 #define READ_SPECIAL_REG(x) ({ \
113         u64 val; \
114         asm volatile ("mrs %0, " # x : "=r"(val)); \
115         val; \
116 })
117
118 void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
119                 const struct pt_regs *regs)
120 {
121         u32 pstate = READ_SPECIAL_REG(CurrentEl);
122         bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t;
123
124         fiq_debugger_dump_regs(output, regs);
125
126         output->printf(output, " sp_el0   %016lx\n",
127                         READ_SPECIAL_REG(sp_el0));
128
129         if (in_el2)
130                 output->printf(output, " sp_el1   %016lx\n",
131                                 READ_SPECIAL_REG(sp_el1));
132
133         output->printf(output, " elr_el1  %016lx\n",
134                         READ_SPECIAL_REG(elr_el1));
135
136         output->printf(output, " spsr_el1 %08lx\n",
137                         READ_SPECIAL_REG(spsr_el1));
138
139         if (in_el2) {
140                 output->printf(output, " spsr_irq %08lx\n",
141                                 READ_SPECIAL_REG(spsr_irq));
142                 output->printf(output, " spsr_abt %08lx\n",
143                                 READ_SPECIAL_REG(spsr_abt));
144                 output->printf(output, " spsr_und %08lx\n",
145                                 READ_SPECIAL_REG(spsr_und));
146                 output->printf(output, " spsr_fiq %08lx\n",
147                                 READ_SPECIAL_REG(spsr_fiq));
148                 output->printf(output, " spsr_el2 %08lx\n",
149                                 READ_SPECIAL_REG(elr_el2));
150                 output->printf(output, " spsr_el2 %08lx\n",
151                                 READ_SPECIAL_REG(spsr_el2));
152         }
153 }
154
155 struct stacktrace_state {
156         struct fiq_debugger_output *output;
157         unsigned int depth;
158 };
159
160 static int report_trace(struct stackframe *frame, void *d)
161 {
162         struct stacktrace_state *sts = d;
163
164         if (sts->depth) {
165                 sts->output->printf(sts->output, "%pF:\n", frame->pc);
166                 sts->output->printf(sts->output,
167                                 "  pc %016lx   sp %016lx   fp %016lx\n",
168                                 frame->pc, frame->sp, frame->fp);
169                 sts->depth--;
170                 return 0;
171         }
172         sts->output->printf(sts->output, "  ...\n");
173
174         return sts->depth == 0;
175 }
176
177 void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
178                 const struct pt_regs *regs, unsigned int depth, void *ssp)
179 {
180         struct thread_info *real_thread_info = THREAD_INFO(ssp);
181         struct stacktrace_state sts;
182
183         sts.depth = depth;
184         sts.output = output;
185         *current_thread_info() = *real_thread_info;
186
187         if (!current)
188                 output->printf(output, "current NULL\n");
189         else
190                 output->printf(output, "pid: %d  comm: %s\n",
191                         current->pid, current->comm);
192         fiq_debugger_dump_regs(output, regs);
193
194         if (!user_mode(regs)) {
195                 struct stackframe frame;
196                 frame.fp = regs->regs[29];
197                 frame.sp = regs->sp;
198                 frame.pc = regs->pc;
199                 output->printf(output, "\n");
200                 walk_stackframe(&frame, report_trace, &sts);
201         }
202 }