Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/kernel/kgdb.c
26442 views
1
/*
2
* Originally written by Glenn Engel, Lake Stevens Instrument Division
3
*
4
* Contributed by HP Systems
5
*
6
* Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
7
* Send complaints, suggestions etc. to <[email protected]>
8
*
9
* Copyright (C) 1995 Andreas Busse
10
*
11
* Copyright (C) 2003 MontaVista Software Inc.
12
* Author: Jun Sun, [email protected] or [email protected]
13
*
14
* Copyright (C) 2004-2005 MontaVista Software Inc.
15
* Author: Manish Lachwani, [email protected] or [email protected]
16
*
17
* Copyright (C) 2007-2008 Wind River Systems, Inc.
18
* Author/Maintainer: Jason Wessel, [email protected]
19
*
20
* This file is licensed under the terms of the GNU General Public License
21
* version 2. This program is licensed "as is" without any warranty of any
22
* kind, whether express or implied.
23
*/
24
25
#include <linux/ptrace.h> /* for linux pt_regs struct */
26
#include <linux/kgdb.h>
27
#include <linux/kdebug.h>
28
#include <linux/sched.h>
29
#include <linux/smp.h>
30
#include <asm/inst.h>
31
#include <asm/fpu.h>
32
#include <asm/cacheflush.h>
33
#include <asm/processor.h>
34
#include <asm/sigcontext.h>
35
#include <asm/irq_regs.h>
36
37
static struct hard_trap_info {
38
unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
39
unsigned char signo; /* Signal that we map this trap into */
40
} hard_trap_info[] = {
41
{ 6, SIGBUS }, /* instruction bus error */
42
{ 7, SIGBUS }, /* data bus error */
43
{ 9, SIGTRAP }, /* break */
44
/* { 11, SIGILL }, */ /* CPU unusable */
45
{ 12, SIGFPE }, /* overflow */
46
{ 13, SIGTRAP }, /* trap */
47
{ 14, SIGSEGV }, /* virtual instruction cache coherency */
48
{ 15, SIGFPE }, /* floating point exception */
49
{ 23, SIGSEGV }, /* watch */
50
{ 31, SIGSEGV }, /* virtual data cache coherency */
51
{ 0, 0} /* Must be last */
52
};
53
54
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
55
{
56
{ "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) },
57
{ "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) },
58
{ "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) },
59
{ "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) },
60
{ "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) },
61
{ "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) },
62
{ "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) },
63
{ "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) },
64
{ "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) },
65
{ "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) },
66
{ "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) },
67
{ "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) },
68
{ "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) },
69
{ "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) },
70
{ "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) },
71
{ "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) },
72
{ "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) },
73
{ "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) },
74
{ "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) },
75
{ "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) },
76
{ "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) },
77
{ "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) },
78
{ "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) },
79
{ "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) },
80
{ "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) },
81
{ "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) },
82
{ "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) },
83
{ "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) },
84
{ "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) },
85
{ "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) },
86
{ "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) },
87
{ "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) },
88
{ "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) },
89
{ "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) },
90
{ "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) },
91
{ "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) },
92
{ "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) },
93
{ "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) },
94
{ "f0", GDB_SIZEOF_REG, 0 },
95
{ "f1", GDB_SIZEOF_REG, 1 },
96
{ "f2", GDB_SIZEOF_REG, 2 },
97
{ "f3", GDB_SIZEOF_REG, 3 },
98
{ "f4", GDB_SIZEOF_REG, 4 },
99
{ "f5", GDB_SIZEOF_REG, 5 },
100
{ "f6", GDB_SIZEOF_REG, 6 },
101
{ "f7", GDB_SIZEOF_REG, 7 },
102
{ "f8", GDB_SIZEOF_REG, 8 },
103
{ "f9", GDB_SIZEOF_REG, 9 },
104
{ "f10", GDB_SIZEOF_REG, 10 },
105
{ "f11", GDB_SIZEOF_REG, 11 },
106
{ "f12", GDB_SIZEOF_REG, 12 },
107
{ "f13", GDB_SIZEOF_REG, 13 },
108
{ "f14", GDB_SIZEOF_REG, 14 },
109
{ "f15", GDB_SIZEOF_REG, 15 },
110
{ "f16", GDB_SIZEOF_REG, 16 },
111
{ "f17", GDB_SIZEOF_REG, 17 },
112
{ "f18", GDB_SIZEOF_REG, 18 },
113
{ "f19", GDB_SIZEOF_REG, 19 },
114
{ "f20", GDB_SIZEOF_REG, 20 },
115
{ "f21", GDB_SIZEOF_REG, 21 },
116
{ "f22", GDB_SIZEOF_REG, 22 },
117
{ "f23", GDB_SIZEOF_REG, 23 },
118
{ "f24", GDB_SIZEOF_REG, 24 },
119
{ "f25", GDB_SIZEOF_REG, 25 },
120
{ "f26", GDB_SIZEOF_REG, 26 },
121
{ "f27", GDB_SIZEOF_REG, 27 },
122
{ "f28", GDB_SIZEOF_REG, 28 },
123
{ "f29", GDB_SIZEOF_REG, 29 },
124
{ "f30", GDB_SIZEOF_REG, 30 },
125
{ "f31", GDB_SIZEOF_REG, 31 },
126
{ "fsr", GDB_SIZEOF_REG, 0 },
127
{ "fir", GDB_SIZEOF_REG, 0 },
128
};
129
130
int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
131
{
132
int fp_reg;
133
134
if (regno < 0 || regno >= DBG_MAX_REG_NUM)
135
return -EINVAL;
136
137
if (dbg_reg_def[regno].offset != -1 && regno < 38) {
138
memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
139
dbg_reg_def[regno].size);
140
} else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
141
/* FP registers 38 -> 69 */
142
if (!(regs->cp0_status & ST0_CU1))
143
return 0;
144
if (regno == 70) {
145
/* Process the fcr31/fsr (register 70) */
146
memcpy((void *)&current->thread.fpu.fcr31, mem,
147
dbg_reg_def[regno].size);
148
goto out_save;
149
} else if (regno == 71) {
150
/* Ignore the fir (register 71) */
151
goto out_save;
152
}
153
fp_reg = dbg_reg_def[regno].offset;
154
memcpy((void *)&current->thread.fpu.fpr[fp_reg], mem,
155
dbg_reg_def[regno].size);
156
out_save:
157
restore_fp(current);
158
}
159
160
return 0;
161
}
162
163
char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
164
{
165
int fp_reg;
166
167
if (regno >= DBG_MAX_REG_NUM || regno < 0)
168
return NULL;
169
170
if (dbg_reg_def[regno].offset != -1 && regno < 38) {
171
/* First 38 registers */
172
memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
173
dbg_reg_def[regno].size);
174
} else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
175
/* FP registers 38 -> 69 */
176
if (!(regs->cp0_status & ST0_CU1))
177
goto out;
178
save_fp(current);
179
if (regno == 70) {
180
/* Process the fcr31/fsr (register 70) */
181
memcpy(mem, (void *)&current->thread.fpu.fcr31,
182
dbg_reg_def[regno].size);
183
goto out;
184
} else if (regno == 71) {
185
/* Ignore the fir (register 71) */
186
memset(mem, 0, dbg_reg_def[regno].size);
187
goto out;
188
}
189
fp_reg = dbg_reg_def[regno].offset;
190
memcpy(mem, (void *)&current->thread.fpu.fpr[fp_reg],
191
dbg_reg_def[regno].size);
192
}
193
194
out:
195
return dbg_reg_def[regno].name;
196
197
}
198
199
void arch_kgdb_breakpoint(void)
200
{
201
__asm__ __volatile__(
202
".globl breakinst\n\t"
203
".set\tnoreorder\n\t"
204
"nop\n"
205
"breakinst:\tbreak\n\t"
206
"nop\n\t"
207
".set\treorder");
208
}
209
210
static int compute_signal(int tt)
211
{
212
struct hard_trap_info *ht;
213
214
for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
215
if (ht->tt == tt)
216
return ht->signo;
217
218
return SIGHUP; /* default for things we don't know about */
219
}
220
221
/*
222
* Similar to regs_to_gdb_regs() except that process is sleeping and so
223
* we may not be able to get all the info.
224
*/
225
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
226
{
227
int reg;
228
#if (KGDB_GDB_REG_SIZE == 32)
229
u32 *ptr = (u32 *)gdb_regs;
230
#else
231
u64 *ptr = (u64 *)gdb_regs;
232
#endif
233
234
for (reg = 0; reg < 16; reg++)
235
*(ptr++) = 0;
236
237
/* S0 - S7 */
238
*(ptr++) = p->thread.reg16;
239
*(ptr++) = p->thread.reg17;
240
*(ptr++) = p->thread.reg18;
241
*(ptr++) = p->thread.reg19;
242
*(ptr++) = p->thread.reg20;
243
*(ptr++) = p->thread.reg21;
244
*(ptr++) = p->thread.reg22;
245
*(ptr++) = p->thread.reg23;
246
247
for (reg = 24; reg < 28; reg++)
248
*(ptr++) = 0;
249
250
/* GP, SP, FP, RA */
251
*(ptr++) = (long)p;
252
*(ptr++) = p->thread.reg29;
253
*(ptr++) = p->thread.reg30;
254
*(ptr++) = p->thread.reg31;
255
256
*(ptr++) = p->thread.cp0_status;
257
258
/* lo, hi */
259
*(ptr++) = 0;
260
*(ptr++) = 0;
261
262
/*
263
* BadVAddr, Cause
264
* Ideally these would come from the last exception frame up the stack
265
* but that requires unwinding, otherwise we can't know much for sure.
266
*/
267
*(ptr++) = 0;
268
*(ptr++) = 0;
269
270
/*
271
* PC
272
* use return address (RA), i.e. the moment after return from resume()
273
*/
274
*(ptr++) = p->thread.reg31;
275
}
276
277
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
278
{
279
regs->cp0_epc = pc;
280
}
281
282
/*
283
* Calls linux_debug_hook before the kernel dies. If KGDB is enabled,
284
* then try to fall into the debugger
285
*/
286
static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
287
void *ptr)
288
{
289
struct die_args *args = (struct die_args *)ptr;
290
struct pt_regs *regs = args->regs;
291
int trap = (regs->cp0_cause & 0x7c) >> 2;
292
293
#ifdef CONFIG_KPROBES
294
/*
295
* Return immediately if the kprobes fault notifier has set
296
* DIE_PAGE_FAULT.
297
*/
298
if (cmd == DIE_PAGE_FAULT)
299
return NOTIFY_DONE;
300
#endif /* CONFIG_KPROBES */
301
302
/* Userspace events, ignore. */
303
if (user_mode(regs))
304
return NOTIFY_DONE;
305
306
if (atomic_read(&kgdb_active) != -1)
307
kgdb_nmicallback(smp_processor_id(), regs);
308
309
if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs))
310
return NOTIFY_DONE;
311
312
if (atomic_read(&kgdb_setting_breakpoint))
313
if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst))
314
regs->cp0_epc += 4;
315
316
/* In SMP mode, __flush_cache_all does IPI */
317
local_irq_enable();
318
__flush_cache_all();
319
320
return NOTIFY_STOP;
321
}
322
323
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
324
int kgdb_ll_trap(int cmd, const char *str,
325
struct pt_regs *regs, long err, int trap, int sig)
326
{
327
struct die_args args = {
328
.regs = regs,
329
.str = str,
330
.err = err,
331
.trapnr = trap,
332
.signr = sig,
333
334
};
335
336
if (!kgdb_io_module_registered)
337
return NOTIFY_DONE;
338
339
return kgdb_mips_notify(NULL, cmd, &args);
340
}
341
#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
342
343
static struct notifier_block kgdb_notifier = {
344
.notifier_call = kgdb_mips_notify,
345
};
346
347
/*
348
* Handle the 'c' command
349
*/
350
int kgdb_arch_handle_exception(int vector, int signo, int err_code,
351
char *remcom_in_buffer, char *remcom_out_buffer,
352
struct pt_regs *regs)
353
{
354
char *ptr;
355
unsigned long address;
356
357
switch (remcom_in_buffer[0]) {
358
case 'c':
359
/* handle the optional parameter */
360
ptr = &remcom_in_buffer[1];
361
if (kgdb_hex2long(&ptr, &address))
362
regs->cp0_epc = address;
363
364
return 0;
365
}
366
367
return -1;
368
}
369
370
const struct kgdb_arch arch_kgdb_ops = {
371
#ifdef CONFIG_CPU_BIG_ENDIAN
372
.gdb_bpt_instr = { spec_op << 2, 0x00, 0x00, break_op },
373
#else
374
.gdb_bpt_instr = { break_op, 0x00, 0x00, spec_op << 2 },
375
#endif
376
};
377
378
int kgdb_arch_init(void)
379
{
380
register_die_notifier(&kgdb_notifier);
381
382
return 0;
383
}
384
385
/*
386
* kgdb_arch_exit - Perform any architecture specific uninitalization.
387
*
388
* This function will handle the uninitalization of any architecture
389
* specific callbacks, for dynamic registration and unregistration.
390
*/
391
void kgdb_arch_exit(void)
392
{
393
unregister_die_notifier(&kgdb_notifier);
394
}
395
396