Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/nios2/kernel/kgdb.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Nios2 KGDB support
4
*
5
* Copyright (C) 2015 Altera Corporation
6
* Copyright (C) 2011 Tobias Klauser <[email protected]>
7
*
8
* Based on the code posted by Kazuyasu on the Altera Forum at:
9
* http://www.alteraforum.com/forum/showpost.php?p=77003&postcount=20
10
*/
11
#include <linux/ptrace.h>
12
#include <linux/kgdb.h>
13
#include <linux/kdebug.h>
14
#include <linux/io.h>
15
16
static int wait_for_remote_debugger;
17
18
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
19
{
20
{ "zero", GDB_SIZEOF_REG, -1 },
21
{ "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, r1) },
22
{ "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, r2) },
23
{ "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, r3) },
24
{ "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, r4) },
25
{ "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, r5) },
26
{ "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, r6) },
27
{ "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, r7) },
28
{ "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, r8) },
29
{ "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, r9) },
30
{ "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, r10) },
31
{ "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, r11) },
32
{ "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, r12) },
33
{ "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, r13) },
34
{ "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, r14) },
35
{ "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, r15) },
36
{ "r16", GDB_SIZEOF_REG, -1 },
37
{ "r17", GDB_SIZEOF_REG, -1 },
38
{ "r18", GDB_SIZEOF_REG, -1 },
39
{ "r19", GDB_SIZEOF_REG, -1 },
40
{ "r20", GDB_SIZEOF_REG, -1 },
41
{ "r21", GDB_SIZEOF_REG, -1 },
42
{ "r22", GDB_SIZEOF_REG, -1 },
43
{ "r23", GDB_SIZEOF_REG, -1 },
44
{ "et", GDB_SIZEOF_REG, -1 },
45
{ "bt", GDB_SIZEOF_REG, -1 },
46
{ "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp) },
47
{ "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp) },
48
{ "fp", GDB_SIZEOF_REG, offsetof(struct pt_regs, fp) },
49
{ "ea", GDB_SIZEOF_REG, -1 },
50
{ "ba", GDB_SIZEOF_REG, -1 },
51
{ "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, ra) },
52
{ "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, ea) },
53
{ "status", GDB_SIZEOF_REG, -1 },
54
{ "estatus", GDB_SIZEOF_REG, offsetof(struct pt_regs, estatus) },
55
{ "bstatus", GDB_SIZEOF_REG, -1 },
56
{ "ienable", GDB_SIZEOF_REG, -1 },
57
{ "ipending", GDB_SIZEOF_REG, -1},
58
{ "cpuid", GDB_SIZEOF_REG, -1 },
59
{ "ctl6", GDB_SIZEOF_REG, -1 },
60
{ "exception", GDB_SIZEOF_REG, -1 },
61
{ "pteaddr", GDB_SIZEOF_REG, -1 },
62
{ "tlbacc", GDB_SIZEOF_REG, -1 },
63
{ "tlbmisc", GDB_SIZEOF_REG, -1 },
64
{ "eccinj", GDB_SIZEOF_REG, -1 },
65
{ "badaddr", GDB_SIZEOF_REG, -1 },
66
{ "config", GDB_SIZEOF_REG, -1 },
67
{ "mpubase", GDB_SIZEOF_REG, -1 },
68
{ "mpuacc", GDB_SIZEOF_REG, -1 },
69
};
70
71
char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
72
{
73
if (regno >= DBG_MAX_REG_NUM || regno < 0)
74
return NULL;
75
76
if (dbg_reg_def[regno].offset != -1)
77
memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
78
dbg_reg_def[regno].size);
79
else
80
memset(mem, 0, dbg_reg_def[regno].size);
81
82
return dbg_reg_def[regno].name;
83
}
84
85
int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
86
{
87
if (regno >= DBG_MAX_REG_NUM || regno < 0)
88
return -EINVAL;
89
90
if (dbg_reg_def[regno].offset != -1)
91
memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
92
dbg_reg_def[regno].size);
93
94
return 0;
95
}
96
97
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
98
{
99
memset((char *)gdb_regs, 0, NUMREGBYTES);
100
gdb_regs[GDB_SP] = p->thread.kregs->sp;
101
gdb_regs[GDB_PC] = p->thread.kregs->ea;
102
}
103
104
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
105
{
106
regs->ea = pc;
107
}
108
109
int kgdb_arch_handle_exception(int vector, int signo, int err_code,
110
char *remcom_in_buffer, char *remcom_out_buffer,
111
struct pt_regs *regs)
112
{
113
char *ptr;
114
unsigned long addr;
115
116
switch (remcom_in_buffer[0]) {
117
case 's':
118
case 'c':
119
/* handle the optional parameters */
120
ptr = &remcom_in_buffer[1];
121
if (kgdb_hex2long(&ptr, &addr))
122
regs->ea = addr;
123
124
return 0;
125
}
126
127
return -1; /* this means that we do not want to exit from the handler */
128
}
129
130
asmlinkage void kgdb_breakpoint_c(struct pt_regs *regs)
131
{
132
/*
133
* The breakpoint entry code has moved the PC on by 4 bytes, so we must
134
* move it back. This could be done on the host but we do it here
135
*/
136
if (!wait_for_remote_debugger)
137
regs->ea -= 4;
138
else /* pass the first trap 30 code */
139
wait_for_remote_debugger = 0;
140
141
kgdb_handle_exception(30, SIGTRAP, 0, regs);
142
}
143
144
int kgdb_arch_init(void)
145
{
146
wait_for_remote_debugger = 1;
147
return 0;
148
}
149
150
void kgdb_arch_exit(void)
151
{
152
/* Nothing to do */
153
}
154
155
const struct kgdb_arch arch_kgdb_ops = {
156
/* Breakpoint instruction: trap 30 */
157
.gdb_bpt_instr = { 0xba, 0x6f, 0x3b, 0x00 },
158
};
159
160