blob: 97246bcbcd62548ebd60f6bc93a2ce66f83fd40b [file] [log] [blame]
Colin Cross516b14d2014-04-02 18:49:39 -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 <asm/stacktrace.h>
18
19#include "fiq_debugger_priv.h"
20
21static 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
Arve Hjønnevåge073df62014-05-02 19:52:54 -070037void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
Colin Cross516b14d2014-04-02 18:49:39 -070038 const struct pt_regs *regs)
39{
Arve Hjønnevåge073df62014-05-02 19:52:54 -070040 output->printf(output, " pc %016lx cpsr %08lx mode %s\n",
Colin Cross516b14d2014-04-02 18:49:39 -070041 regs->pc, regs->pstate, mode_name(regs));
42}
43
Arve Hjønnevåge073df62014-05-02 19:52:54 -070044void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output,
Colin Cross516b14d2014-04-02 18:49:39 -070045 const struct pt_regs *regs)
46{
Arve Hjønnevåge073df62014-05-02 19:52:54 -070047 output->printf(output, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
Colin Cross516b14d2014-04-02 18:49:39 -070048 regs->compat_usr(0), regs->compat_usr(1),
49 regs->compat_usr(2), regs->compat_usr(3));
Arve Hjønnevåge073df62014-05-02 19:52:54 -070050 output->printf(output, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
Colin Cross516b14d2014-04-02 18:49:39 -070051 regs->compat_usr(4), regs->compat_usr(5),
52 regs->compat_usr(6), regs->compat_usr(7));
Arve Hjønnevåge073df62014-05-02 19:52:54 -070053 output->printf(output, " r8 %08x r9 %08x r10 %08x r11 %08x\n",
Colin Cross516b14d2014-04-02 18:49:39 -070054 regs->compat_usr(8), regs->compat_usr(9),
55 regs->compat_usr(10), regs->compat_usr(11));
Arve Hjønnevåge073df62014-05-02 19:52:54 -070056 output->printf(output, " ip %08x sp %08x lr %08x pc %08x\n",
Colin Cross516b14d2014-04-02 18:49:39 -070057 regs->compat_usr(12), regs->compat_sp,
58 regs->compat_lr, regs->pc);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070059 output->printf(output, " cpsr %08x (%s)\n",
Colin Cross516b14d2014-04-02 18:49:39 -070060 regs->pstate, mode_name(regs));
61}
62
Arve Hjønnevåge073df62014-05-02 19:52:54 -070063void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output,
Colin Cross516b14d2014-04-02 18:49:39 -070064 const struct pt_regs *regs)
65{
66
Arve Hjønnevåge073df62014-05-02 19:52:54 -070067 output->printf(output, " x0 %016lx x1 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070068 regs->regs[0], regs->regs[1]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070069 output->printf(output, " x2 %016lx x3 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070070 regs->regs[2], regs->regs[3]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070071 output->printf(output, " x4 %016lx x5 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070072 regs->regs[4], regs->regs[5]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070073 output->printf(output, " x6 %016lx x7 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070074 regs->regs[6], regs->regs[7]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070075 output->printf(output, " x8 %016lx x9 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070076 regs->regs[8], regs->regs[9]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070077 output->printf(output, " x10 %016lx x11 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070078 regs->regs[10], regs->regs[11]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070079 output->printf(output, " x12 %016lx x13 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070080 regs->regs[12], regs->regs[13]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070081 output->printf(output, " x14 %016lx x15 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070082 regs->regs[14], regs->regs[15]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070083 output->printf(output, " x16 %016lx x17 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070084 regs->regs[16], regs->regs[17]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070085 output->printf(output, " x18 %016lx x19 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070086 regs->regs[18], regs->regs[19]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070087 output->printf(output, " x20 %016lx x21 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070088 regs->regs[20], regs->regs[21]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070089 output->printf(output, " x22 %016lx x23 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070090 regs->regs[22], regs->regs[23]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070091 output->printf(output, " x24 %016lx x25 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070092 regs->regs[24], regs->regs[25]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070093 output->printf(output, " x26 %016lx x27 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070094 regs->regs[26], regs->regs[27]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070095 output->printf(output, " x28 %016lx x29 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070096 regs->regs[28], regs->regs[29]);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070097 output->printf(output, " x30 %016lx sp %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -070098 regs->regs[30], regs->sp);
Arve Hjønnevåge073df62014-05-02 19:52:54 -070099 output->printf(output, " pc %016lx cpsr %08x (%s)\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700100 regs->pc, regs->pstate, mode_name(regs));
101}
102
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700103void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
Colin Cross516b14d2014-04-02 18:49:39 -0700104 const struct pt_regs *regs)
105{
106 if (compat_user_mode(regs))
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700107 fiq_debugger_dump_regs_aarch32(output, regs);
Colin Cross516b14d2014-04-02 18:49:39 -0700108 else
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700109 fiq_debugger_dump_regs_aarch64(output, regs);
Colin Cross516b14d2014-04-02 18:49:39 -0700110}
111
112#define READ_SPECIAL_REG(x) ({ \
113 u64 val; \
114 asm volatile ("mrs %0, " # x : "=r"(val)); \
115 val; \
116})
117
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700118void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
Colin Cross516b14d2014-04-02 18:49:39 -0700119 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
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700124 fiq_debugger_dump_regs(output, regs);
Colin Cross516b14d2014-04-02 18:49:39 -0700125
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700126 output->printf(output, " sp_el0 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700127 READ_SPECIAL_REG(sp_el0));
128
129 if (in_el2)
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700130 output->printf(output, " sp_el1 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700131 READ_SPECIAL_REG(sp_el1));
132
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700133 output->printf(output, " elr_el1 %016lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700134 READ_SPECIAL_REG(elr_el1));
135
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700136 output->printf(output, " spsr_el1 %08lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700137 READ_SPECIAL_REG(spsr_el1));
138
139 if (in_el2) {
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700140 output->printf(output, " spsr_irq %08lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700141 READ_SPECIAL_REG(spsr_irq));
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700142 output->printf(output, " spsr_abt %08lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700143 READ_SPECIAL_REG(spsr_abt));
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700144 output->printf(output, " spsr_und %08lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700145 READ_SPECIAL_REG(spsr_und));
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700146 output->printf(output, " spsr_fiq %08lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700147 READ_SPECIAL_REG(spsr_fiq));
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700148 output->printf(output, " spsr_el2 %08lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700149 READ_SPECIAL_REG(elr_el2));
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700150 output->printf(output, " spsr_el2 %08lx\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700151 READ_SPECIAL_REG(spsr_el2));
152 }
153}
154
155struct stacktrace_state {
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700156 struct fiq_debugger_output *output;
Colin Cross516b14d2014-04-02 18:49:39 -0700157 unsigned int depth;
158};
159
160static int report_trace(struct stackframe *frame, void *d)
161{
162 struct stacktrace_state *sts = d;
163
164 if (sts->depth) {
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700165 sts->output->printf(sts->output, "%pF:\n", frame->pc);
166 sts->output->printf(sts->output,
Colin Cross516b14d2014-04-02 18:49:39 -0700167 " pc %016lx sp %016lx fp %016lx\n",
168 frame->pc, frame->sp, frame->fp);
169 sts->depth--;
170 return 0;
171 }
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700172 sts->output->printf(sts->output, " ...\n");
Colin Cross516b14d2014-04-02 18:49:39 -0700173
174 return sts->depth == 0;
175}
176
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700177void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
Colin Cross516b14d2014-04-02 18:49:39 -0700178 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;
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700184 sts.output = output;
Colin Cross516b14d2014-04-02 18:49:39 -0700185 *current_thread_info() = *real_thread_info;
186
187 if (!current)
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700188 output->printf(output, "current NULL\n");
Colin Cross516b14d2014-04-02 18:49:39 -0700189 else
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700190 output->printf(output, "pid: %d comm: %s\n",
Colin Cross516b14d2014-04-02 18:49:39 -0700191 current->pid, current->comm);
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700192 fiq_debugger_dump_regs(output, regs);
Colin Cross516b14d2014-04-02 18:49:39 -0700193
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;
Arve Hjønnevåge073df62014-05-02 19:52:54 -0700199 output->printf(output, "\n");
Jeff Vander Stoepa33d9f92016-09-18 21:39:28 -0700200 walk_stackframe(current, &frame, report_trace, &sts);
Colin Cross516b14d2014-04-02 18:49:39 -0700201 }
202}