1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * arch/arm/kernel/kgdb.c |
4 | * |
5 | * ARM KGDB support |
6 | * |
7 | * Copyright (c) 2002-2004 MontaVista Software, Inc |
8 | * Copyright (c) 2008 Wind River Systems, Inc. |
9 | * |
10 | * Authors: George Davis <davis_g@mvista.com> |
11 | * Deepak Saxena <dsaxena@plexity.net> |
12 | */ |
13 | #include <linux/irq.h> |
14 | #include <linux/kdebug.h> |
15 | #include <linux/kgdb.h> |
16 | #include <linux/uaccess.h> |
17 | |
18 | #include <asm/patch.h> |
19 | #include <asm/traps.h> |
20 | |
21 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
22 | { |
23 | { "r0" , 4, offsetof(struct pt_regs, ARM_r0)}, |
24 | { "r1" , 4, offsetof(struct pt_regs, ARM_r1)}, |
25 | { "r2" , 4, offsetof(struct pt_regs, ARM_r2)}, |
26 | { "r3" , 4, offsetof(struct pt_regs, ARM_r3)}, |
27 | { "r4" , 4, offsetof(struct pt_regs, ARM_r4)}, |
28 | { "r5" , 4, offsetof(struct pt_regs, ARM_r5)}, |
29 | { "r6" , 4, offsetof(struct pt_regs, ARM_r6)}, |
30 | { "r7" , 4, offsetof(struct pt_regs, ARM_r7)}, |
31 | { "r8" , 4, offsetof(struct pt_regs, ARM_r8)}, |
32 | { "r9" , 4, offsetof(struct pt_regs, ARM_r9)}, |
33 | { "r10" , 4, offsetof(struct pt_regs, ARM_r10)}, |
34 | { "fp" , 4, offsetof(struct pt_regs, ARM_fp)}, |
35 | { "ip" , 4, offsetof(struct pt_regs, ARM_ip)}, |
36 | { "sp" , 4, offsetof(struct pt_regs, ARM_sp)}, |
37 | { "lr" , 4, offsetof(struct pt_regs, ARM_lr)}, |
38 | { "pc" , 4, offsetof(struct pt_regs, ARM_pc)}, |
39 | { "f0" , 12, -1 }, |
40 | { "f1" , 12, -1 }, |
41 | { "f2" , 12, -1 }, |
42 | { "f3" , 12, -1 }, |
43 | { "f4" , 12, -1 }, |
44 | { "f5" , 12, -1 }, |
45 | { "f6" , 12, -1 }, |
46 | { "f7" , 12, -1 }, |
47 | { "fps" , 4, -1 }, |
48 | { "cpsr" , 4, offsetof(struct pt_regs, ARM_cpsr)}, |
49 | }; |
50 | |
51 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
52 | { |
53 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
54 | return NULL; |
55 | |
56 | if (dbg_reg_def[regno].offset != -1) |
57 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
58 | dbg_reg_def[regno].size); |
59 | else |
60 | memset(mem, 0, dbg_reg_def[regno].size); |
61 | return dbg_reg_def[regno].name; |
62 | } |
63 | |
64 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
65 | { |
66 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
67 | return -EINVAL; |
68 | |
69 | if (dbg_reg_def[regno].offset != -1) |
70 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
71 | dbg_reg_def[regno].size); |
72 | return 0; |
73 | } |
74 | |
75 | void |
76 | sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) |
77 | { |
78 | struct thread_info *ti; |
79 | int regno; |
80 | |
81 | /* Just making sure... */ |
82 | if (task == NULL) |
83 | return; |
84 | |
85 | /* Initialize to zero */ |
86 | for (regno = 0; regno < GDB_MAX_REGS; regno++) |
87 | gdb_regs[regno] = 0; |
88 | |
89 | /* Otherwise, we have only some registers from switch_to() */ |
90 | ti = task_thread_info(task); |
91 | gdb_regs[_R4] = ti->cpu_context.r4; |
92 | gdb_regs[_R5] = ti->cpu_context.r5; |
93 | gdb_regs[_R6] = ti->cpu_context.r6; |
94 | gdb_regs[_R7] = ti->cpu_context.r7; |
95 | gdb_regs[_R8] = ti->cpu_context.r8; |
96 | gdb_regs[_R9] = ti->cpu_context.r9; |
97 | gdb_regs[_R10] = ti->cpu_context.sl; |
98 | gdb_regs[_FP] = ti->cpu_context.fp; |
99 | gdb_regs[_SPT] = ti->cpu_context.sp; |
100 | gdb_regs[_PC] = ti->cpu_context.pc; |
101 | } |
102 | |
103 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) |
104 | { |
105 | regs->ARM_pc = pc; |
106 | } |
107 | |
108 | static int compiled_break; |
109 | |
110 | int kgdb_arch_handle_exception(int exception_vector, int signo, |
111 | int err_code, char *remcom_in_buffer, |
112 | char *remcom_out_buffer, |
113 | struct pt_regs *linux_regs) |
114 | { |
115 | unsigned long addr; |
116 | char *ptr; |
117 | |
118 | switch (remcom_in_buffer[0]) { |
119 | case 'D': |
120 | case 'k': |
121 | case 'c': |
122 | /* |
123 | * Try to read optional parameter, pc unchanged if no parm. |
124 | * If this was a compiled breakpoint, we need to move |
125 | * to the next instruction or we will just breakpoint |
126 | * over and over again. |
127 | */ |
128 | ptr = &remcom_in_buffer[1]; |
129 | if (kgdb_hex2long(ptr: &ptr, long_val: &addr)) |
130 | linux_regs->ARM_pc = addr; |
131 | else if (compiled_break == 1) |
132 | linux_regs->ARM_pc += 4; |
133 | |
134 | compiled_break = 0; |
135 | |
136 | return 0; |
137 | } |
138 | |
139 | return -1; |
140 | } |
141 | |
142 | static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr) |
143 | { |
144 | kgdb_handle_exception(ex_vector: 1, SIGTRAP, err_code: 0, regs); |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr) |
150 | { |
151 | compiled_break = 1; |
152 | kgdb_handle_exception(ex_vector: 1, SIGTRAP, err_code: 0, regs); |
153 | |
154 | return 0; |
155 | } |
156 | |
157 | static struct undef_hook kgdb_brkpt_arm_hook = { |
158 | .instr_mask = 0xffffffff, |
159 | .instr_val = KGDB_BREAKINST, |
160 | .cpsr_mask = PSR_T_BIT | MODE_MASK, |
161 | .cpsr_val = SVC_MODE, |
162 | .fn = kgdb_brk_fn |
163 | }; |
164 | |
165 | static struct undef_hook kgdb_brkpt_thumb_hook = { |
166 | .instr_mask = 0xffff, |
167 | .instr_val = KGDB_BREAKINST & 0xffff, |
168 | .cpsr_mask = PSR_T_BIT | MODE_MASK, |
169 | .cpsr_val = PSR_T_BIT | SVC_MODE, |
170 | .fn = kgdb_brk_fn |
171 | }; |
172 | |
173 | static struct undef_hook kgdb_compiled_brkpt_arm_hook = { |
174 | .instr_mask = 0xffffffff, |
175 | .instr_val = KGDB_COMPILED_BREAK, |
176 | .cpsr_mask = PSR_T_BIT | MODE_MASK, |
177 | .cpsr_val = SVC_MODE, |
178 | .fn = kgdb_compiled_brk_fn |
179 | }; |
180 | |
181 | static struct undef_hook kgdb_compiled_brkpt_thumb_hook = { |
182 | .instr_mask = 0xffff, |
183 | .instr_val = KGDB_COMPILED_BREAK & 0xffff, |
184 | .cpsr_mask = PSR_T_BIT | MODE_MASK, |
185 | .cpsr_val = PSR_T_BIT | SVC_MODE, |
186 | .fn = kgdb_compiled_brk_fn |
187 | }; |
188 | |
189 | static int __kgdb_notify(struct die_args *args, unsigned long cmd) |
190 | { |
191 | struct pt_regs *regs = args->regs; |
192 | |
193 | if (kgdb_handle_exception(ex_vector: 1, signo: args->signr, err_code: cmd, regs)) |
194 | return NOTIFY_DONE; |
195 | return NOTIFY_STOP; |
196 | } |
197 | static int |
198 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) |
199 | { |
200 | unsigned long flags; |
201 | int ret; |
202 | |
203 | local_irq_save(flags); |
204 | ret = __kgdb_notify(args: ptr, cmd); |
205 | local_irq_restore(flags); |
206 | |
207 | return ret; |
208 | } |
209 | |
210 | static struct notifier_block kgdb_notifier = { |
211 | .notifier_call = kgdb_notify, |
212 | .priority = -INT_MAX, |
213 | }; |
214 | |
215 | |
216 | /** |
217 | * kgdb_arch_init - Perform any architecture specific initalization. |
218 | * |
219 | * This function will handle the initalization of any architecture |
220 | * specific callbacks. |
221 | */ |
222 | int kgdb_arch_init(void) |
223 | { |
224 | int ret = register_die_notifier(nb: &kgdb_notifier); |
225 | |
226 | if (ret != 0) |
227 | return ret; |
228 | |
229 | register_undef_hook(&kgdb_brkpt_arm_hook); |
230 | register_undef_hook(&kgdb_brkpt_thumb_hook); |
231 | register_undef_hook(&kgdb_compiled_brkpt_arm_hook); |
232 | register_undef_hook(&kgdb_compiled_brkpt_thumb_hook); |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | /** |
238 | * kgdb_arch_exit - Perform any architecture specific uninitalization. |
239 | * |
240 | * This function will handle the uninitalization of any architecture |
241 | * specific callbacks, for dynamic registration and unregistration. |
242 | */ |
243 | void kgdb_arch_exit(void) |
244 | { |
245 | unregister_undef_hook(&kgdb_brkpt_arm_hook); |
246 | unregister_undef_hook(&kgdb_brkpt_thumb_hook); |
247 | unregister_undef_hook(&kgdb_compiled_brkpt_arm_hook); |
248 | unregister_undef_hook(&kgdb_compiled_brkpt_thumb_hook); |
249 | unregister_die_notifier(nb: &kgdb_notifier); |
250 | } |
251 | |
252 | int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) |
253 | { |
254 | int err; |
255 | |
256 | /* patch_text() only supports int-sized breakpoints */ |
257 | BUILD_BUG_ON(sizeof(int) != BREAK_INSTR_SIZE); |
258 | |
259 | err = copy_from_kernel_nofault(dst: bpt->saved_instr, src: (char *)bpt->bpt_addr, |
260 | BREAK_INSTR_SIZE); |
261 | if (err) |
262 | return err; |
263 | |
264 | /* Machine is already stopped, so we can use __patch_text() directly */ |
265 | __patch_text((void *)bpt->bpt_addr, |
266 | *(unsigned int *)arch_kgdb_ops.gdb_bpt_instr); |
267 | |
268 | return err; |
269 | } |
270 | |
271 | int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) |
272 | { |
273 | /* Machine is already stopped, so we can use __patch_text() directly */ |
274 | __patch_text((void *)bpt->bpt_addr, *(unsigned int *)bpt->saved_instr); |
275 | |
276 | return 0; |
277 | } |
278 | |
279 | /* |
280 | * Register our undef instruction hooks with ARM undef core. |
281 | * We register a hook specifically looking for the KGB break inst |
282 | * and we handle the normal undef case within the do_undefinstr |
283 | * handler. |
284 | */ |
285 | const struct kgdb_arch arch_kgdb_ops = { |
286 | #ifndef __ARMEB__ |
287 | .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7} |
288 | #else /* ! __ARMEB__ */ |
289 | .gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe} |
290 | #endif |
291 | }; |
292 | |