Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm64/kernel/kgdb.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* AArch64 KGDB support
4
*
5
* Based on arch/arm/kernel/kgdb.c
6
*
7
* Copyright (C) 2013 Cavium Inc.
8
* Author: Vijaya Kumar K <[email protected]>
9
*/
10
11
#include <linux/bug.h>
12
#include <linux/irq.h>
13
#include <linux/kdebug.h>
14
#include <linux/kgdb.h>
15
#include <linux/kprobes.h>
16
#include <linux/sched/task_stack.h>
17
18
#include <asm/debug-monitors.h>
19
#include <asm/insn.h>
20
#include <asm/text-patching.h>
21
#include <asm/traps.h>
22
23
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
24
{ "x0", 8, offsetof(struct pt_regs, regs[0])},
25
{ "x1", 8, offsetof(struct pt_regs, regs[1])},
26
{ "x2", 8, offsetof(struct pt_regs, regs[2])},
27
{ "x3", 8, offsetof(struct pt_regs, regs[3])},
28
{ "x4", 8, offsetof(struct pt_regs, regs[4])},
29
{ "x5", 8, offsetof(struct pt_regs, regs[5])},
30
{ "x6", 8, offsetof(struct pt_regs, regs[6])},
31
{ "x7", 8, offsetof(struct pt_regs, regs[7])},
32
{ "x8", 8, offsetof(struct pt_regs, regs[8])},
33
{ "x9", 8, offsetof(struct pt_regs, regs[9])},
34
{ "x10", 8, offsetof(struct pt_regs, regs[10])},
35
{ "x11", 8, offsetof(struct pt_regs, regs[11])},
36
{ "x12", 8, offsetof(struct pt_regs, regs[12])},
37
{ "x13", 8, offsetof(struct pt_regs, regs[13])},
38
{ "x14", 8, offsetof(struct pt_regs, regs[14])},
39
{ "x15", 8, offsetof(struct pt_regs, regs[15])},
40
{ "x16", 8, offsetof(struct pt_regs, regs[16])},
41
{ "x17", 8, offsetof(struct pt_regs, regs[17])},
42
{ "x18", 8, offsetof(struct pt_regs, regs[18])},
43
{ "x19", 8, offsetof(struct pt_regs, regs[19])},
44
{ "x20", 8, offsetof(struct pt_regs, regs[20])},
45
{ "x21", 8, offsetof(struct pt_regs, regs[21])},
46
{ "x22", 8, offsetof(struct pt_regs, regs[22])},
47
{ "x23", 8, offsetof(struct pt_regs, regs[23])},
48
{ "x24", 8, offsetof(struct pt_regs, regs[24])},
49
{ "x25", 8, offsetof(struct pt_regs, regs[25])},
50
{ "x26", 8, offsetof(struct pt_regs, regs[26])},
51
{ "x27", 8, offsetof(struct pt_regs, regs[27])},
52
{ "x28", 8, offsetof(struct pt_regs, regs[28])},
53
{ "x29", 8, offsetof(struct pt_regs, regs[29])},
54
{ "x30", 8, offsetof(struct pt_regs, regs[30])},
55
{ "sp", 8, offsetof(struct pt_regs, sp)},
56
{ "pc", 8, offsetof(struct pt_regs, pc)},
57
/*
58
* struct pt_regs thinks PSTATE is 64-bits wide but gdb remote
59
* protocol disagrees. Therefore we must extract only the lower
60
* 32-bits. Look for the big comment in asm/kgdb.h for more
61
* detail.
62
*/
63
{ "pstate", 4, offsetof(struct pt_regs, pstate)
64
#ifdef CONFIG_CPU_BIG_ENDIAN
65
+ 4
66
#endif
67
},
68
{ "v0", 16, -1 },
69
{ "v1", 16, -1 },
70
{ "v2", 16, -1 },
71
{ "v3", 16, -1 },
72
{ "v4", 16, -1 },
73
{ "v5", 16, -1 },
74
{ "v6", 16, -1 },
75
{ "v7", 16, -1 },
76
{ "v8", 16, -1 },
77
{ "v9", 16, -1 },
78
{ "v10", 16, -1 },
79
{ "v11", 16, -1 },
80
{ "v12", 16, -1 },
81
{ "v13", 16, -1 },
82
{ "v14", 16, -1 },
83
{ "v15", 16, -1 },
84
{ "v16", 16, -1 },
85
{ "v17", 16, -1 },
86
{ "v18", 16, -1 },
87
{ "v19", 16, -1 },
88
{ "v20", 16, -1 },
89
{ "v21", 16, -1 },
90
{ "v22", 16, -1 },
91
{ "v23", 16, -1 },
92
{ "v24", 16, -1 },
93
{ "v25", 16, -1 },
94
{ "v26", 16, -1 },
95
{ "v27", 16, -1 },
96
{ "v28", 16, -1 },
97
{ "v29", 16, -1 },
98
{ "v30", 16, -1 },
99
{ "v31", 16, -1 },
100
{ "fpsr", 4, -1 },
101
{ "fpcr", 4, -1 },
102
};
103
104
char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
105
{
106
if (regno >= DBG_MAX_REG_NUM || regno < 0)
107
return NULL;
108
109
if (dbg_reg_def[regno].offset != -1)
110
memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
111
dbg_reg_def[regno].size);
112
else
113
memset(mem, 0, dbg_reg_def[regno].size);
114
return dbg_reg_def[regno].name;
115
}
116
117
int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
118
{
119
if (regno >= DBG_MAX_REG_NUM || regno < 0)
120
return -EINVAL;
121
122
if (dbg_reg_def[regno].offset != -1)
123
memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
124
dbg_reg_def[regno].size);
125
return 0;
126
}
127
128
void
129
sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
130
{
131
struct cpu_context *cpu_context = &task->thread.cpu_context;
132
133
/* Initialize to zero */
134
memset((char *)gdb_regs, 0, NUMREGBYTES);
135
136
gdb_regs[19] = cpu_context->x19;
137
gdb_regs[20] = cpu_context->x20;
138
gdb_regs[21] = cpu_context->x21;
139
gdb_regs[22] = cpu_context->x22;
140
gdb_regs[23] = cpu_context->x23;
141
gdb_regs[24] = cpu_context->x24;
142
gdb_regs[25] = cpu_context->x25;
143
gdb_regs[26] = cpu_context->x26;
144
gdb_regs[27] = cpu_context->x27;
145
gdb_regs[28] = cpu_context->x28;
146
gdb_regs[29] = cpu_context->fp;
147
148
gdb_regs[31] = cpu_context->sp;
149
gdb_regs[32] = cpu_context->pc;
150
}
151
152
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
153
{
154
regs->pc = pc;
155
}
156
157
static int compiled_break;
158
159
static void kgdb_arch_update_addr(struct pt_regs *regs,
160
char *remcom_in_buffer)
161
{
162
unsigned long addr;
163
char *ptr;
164
165
ptr = &remcom_in_buffer[1];
166
if (kgdb_hex2long(&ptr, &addr))
167
kgdb_arch_set_pc(regs, addr);
168
else if (compiled_break == 1)
169
kgdb_arch_set_pc(regs, regs->pc + 4);
170
171
compiled_break = 0;
172
}
173
174
int kgdb_arch_handle_exception(int exception_vector, int signo,
175
int err_code, char *remcom_in_buffer,
176
char *remcom_out_buffer,
177
struct pt_regs *linux_regs)
178
{
179
int err;
180
181
switch (remcom_in_buffer[0]) {
182
case 'D':
183
case 'k':
184
/*
185
* Packet D (Detach), k (kill). No special handling
186
* is required here. Handle same as c packet.
187
*/
188
case 'c':
189
/*
190
* Packet c (Continue) to continue executing.
191
* Set pc to required address.
192
* Try to read optional parameter and set pc.
193
* If this was a compiled breakpoint, we need to move
194
* to the next instruction else we will just breakpoint
195
* over and over again.
196
*/
197
kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
198
atomic_set(&kgdb_cpu_doing_single_step, -1);
199
kgdb_single_step = 0;
200
201
/*
202
* Received continue command, disable single step
203
*/
204
if (kernel_active_single_step())
205
kernel_disable_single_step();
206
207
err = 0;
208
break;
209
case 's':
210
/*
211
* Update step address value with address passed
212
* with step packet.
213
* On debug exception return PC is copied to ELR
214
* So just update PC.
215
* If no step address is passed, resume from the address
216
* pointed by PC. Do not update PC
217
*/
218
kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
219
atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
220
kgdb_single_step = 1;
221
222
/*
223
* Enable single step handling
224
*/
225
if (!kernel_active_single_step())
226
kernel_enable_single_step(linux_regs);
227
else
228
kernel_rewind_single_step(linux_regs);
229
err = 0;
230
break;
231
default:
232
err = -1;
233
}
234
return err;
235
}
236
237
int kgdb_brk_handler(struct pt_regs *regs, unsigned long esr)
238
{
239
kgdb_handle_exception(1, SIGTRAP, 0, regs);
240
return DBG_HOOK_HANDLED;
241
}
242
NOKPROBE_SYMBOL(kgdb_brk_handler)
243
244
int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr)
245
{
246
compiled_break = 1;
247
kgdb_handle_exception(1, SIGTRAP, 0, regs);
248
249
return DBG_HOOK_HANDLED;
250
}
251
NOKPROBE_SYMBOL(kgdb_compiled_brk_handler);
252
253
int kgdb_single_step_handler(struct pt_regs *regs, unsigned long esr)
254
{
255
if (!kgdb_single_step)
256
return DBG_HOOK_ERROR;
257
258
kgdb_handle_exception(0, SIGTRAP, 0, regs);
259
return DBG_HOOK_HANDLED;
260
}
261
NOKPROBE_SYMBOL(kgdb_single_step_handler);
262
263
static int __kgdb_notify(struct die_args *args, unsigned long cmd)
264
{
265
struct pt_regs *regs = args->regs;
266
267
if (kgdb_handle_exception(1, args->signr, cmd, regs))
268
return NOTIFY_DONE;
269
return NOTIFY_STOP;
270
}
271
272
static int
273
kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
274
{
275
unsigned long flags;
276
int ret;
277
278
local_irq_save(flags);
279
ret = __kgdb_notify(ptr, cmd);
280
local_irq_restore(flags);
281
282
return ret;
283
}
284
285
static struct notifier_block kgdb_notifier = {
286
.notifier_call = kgdb_notify,
287
/*
288
* Want to be lowest priority
289
*/
290
.priority = -INT_MAX,
291
};
292
293
/*
294
* kgdb_arch_init - Perform any architecture specific initialization.
295
* This function will handle the initialization of any architecture
296
* specific callbacks.
297
*/
298
int kgdb_arch_init(void)
299
{
300
return register_die_notifier(&kgdb_notifier);
301
}
302
303
/*
304
* kgdb_arch_exit - Perform any architecture specific uninitalization.
305
* This function will handle the uninitalization of any architecture
306
* specific callbacks, for dynamic registration and unregistration.
307
*/
308
void kgdb_arch_exit(void)
309
{
310
unregister_die_notifier(&kgdb_notifier);
311
}
312
313
const struct kgdb_arch arch_kgdb_ops;
314
315
int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
316
{
317
int err;
318
319
BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);
320
321
err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
322
if (err)
323
return err;
324
325
return aarch64_insn_write((void *)bpt->bpt_addr,
326
(u32)AARCH64_BREAK_KGDB_DYN_DBG);
327
}
328
329
int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
330
{
331
return aarch64_insn_write((void *)bpt->bpt_addr,
332
*(u32 *)bpt->saved_instr);
333
}
334
335