hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/arch/arm64/kernel/debug-monitors.c
....@@ -1,19 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * ARMv8 single-step debug support and mdscr context switching.
34 *
45 * Copyright (C) 2012 ARM Limited
5
- *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License version 2 as
8
- * published by the Free Software Foundation.
9
- *
10
- * This program is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
176 *
187 * Author: Will Deacon <will.deacon@arm.com>
198 */
....@@ -141,7 +130,7 @@
141130 return 0;
142131 }
143132
144
-static int debug_monitors_init(void)
133
+static int __init debug_monitors_init(void)
145134 {
146135 return cpuhp_setup_state(CPUHP_AP_ARM64_DEBUG_MONITORS_STARTING,
147136 "arm64/debug_monitors:starting",
....@@ -167,23 +156,44 @@
167156 #define set_regs_spsr_ss(r) set_user_regs_spsr_ss(&(r)->user_regs)
168157 #define clear_regs_spsr_ss(r) clear_user_regs_spsr_ss(&(r)->user_regs)
169158
170
-/* EL1 Single Step Handler hooks */
171
-static LIST_HEAD(step_hook);
172
-static DEFINE_SPINLOCK(step_hook_lock);
159
+static DEFINE_SPINLOCK(debug_hook_lock);
160
+static LIST_HEAD(user_step_hook);
161
+static LIST_HEAD(kernel_step_hook);
173162
174
-void register_step_hook(struct step_hook *hook)
163
+static void register_debug_hook(struct list_head *node, struct list_head *list)
175164 {
176
- spin_lock(&step_hook_lock);
177
- list_add_rcu(&hook->node, &step_hook);
178
- spin_unlock(&step_hook_lock);
165
+ spin_lock(&debug_hook_lock);
166
+ list_add_rcu(node, list);
167
+ spin_unlock(&debug_hook_lock);
168
+
179169 }
180170
181
-void unregister_step_hook(struct step_hook *hook)
171
+static void unregister_debug_hook(struct list_head *node)
182172 {
183
- spin_lock(&step_hook_lock);
184
- list_del_rcu(&hook->node);
185
- spin_unlock(&step_hook_lock);
173
+ spin_lock(&debug_hook_lock);
174
+ list_del_rcu(node);
175
+ spin_unlock(&debug_hook_lock);
186176 synchronize_rcu();
177
+}
178
+
179
+void register_user_step_hook(struct step_hook *hook)
180
+{
181
+ register_debug_hook(&hook->node, &user_step_hook);
182
+}
183
+
184
+void unregister_user_step_hook(struct step_hook *hook)
185
+{
186
+ unregister_debug_hook(&hook->node);
187
+}
188
+
189
+void register_kernel_step_hook(struct step_hook *hook)
190
+{
191
+ register_debug_hook(&hook->node, &kernel_step_hook);
192
+}
193
+
194
+void unregister_kernel_step_hook(struct step_hook *hook)
195
+{
196
+ unregister_debug_hook(&hook->node);
187197 }
188198
189199 /*
....@@ -195,17 +205,20 @@
195205 static int call_step_hook(struct pt_regs *regs, unsigned int esr)
196206 {
197207 struct step_hook *hook;
208
+ struct list_head *list;
198209 int retval = DBG_HOOK_ERROR;
199210
200
- rcu_read_lock();
211
+ list = user_mode(regs) ? &user_step_hook : &kernel_step_hook;
201212
202
- list_for_each_entry_rcu(hook, &step_hook, node) {
213
+ /*
214
+ * Since single-step exception disables interrupt, this function is
215
+ * entirely not preemptible, and we can use rcu list safely here.
216
+ */
217
+ list_for_each_entry_rcu(hook, list, node) {
203218 retval = hook->fn(regs, esr);
204219 if (retval == DBG_HOOK_HANDLED)
205220 break;
206221 }
207
-
208
- rcu_read_unlock();
209222
210223 return retval;
211224 }
....@@ -214,13 +227,6 @@
214227 static void send_user_sigtrap(int si_code)
215228 {
216229 struct pt_regs *regs = current_pt_regs();
217
- siginfo_t info;
218
-
219
- clear_siginfo(&info);
220
- info.si_signo = SIGTRAP;
221
- info.si_errno = 0;
222
- info.si_code = si_code;
223
- info.si_addr = (void __user *)instruction_pointer(regs);
224230
225231 if (WARN_ON(!user_mode(regs)))
226232 return;
....@@ -228,10 +234,11 @@
228234 if (interrupts_enabled(regs))
229235 local_irq_enable();
230236
231
- arm64_force_sig_info(&info, "User debug trap", current);
237
+ arm64_force_sig_fault(SIGTRAP, si_code, instruction_pointer(regs),
238
+ "User debug trap");
232239 }
233240
234
-static int single_step_handler(unsigned long addr, unsigned int esr,
241
+static int single_step_handler(unsigned long unused, unsigned int esr,
235242 struct pt_regs *regs)
236243 {
237244 bool handler_found = false;
....@@ -243,10 +250,6 @@
243250 if (!reinstall_suspended_bps(regs))
244251 return 0;
245252
246
-#ifdef CONFIG_KPROBES
247
- if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
248
- handler_found = true;
249
-#endif
250253 if (!handler_found && call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
251254 handler_found = true;
252255
....@@ -273,61 +276,62 @@
273276 }
274277 NOKPROBE_SYMBOL(single_step_handler);
275278
276
-/*
277
- * Breakpoint handler is re-entrant as another breakpoint can
278
- * hit within breakpoint handler, especically in kprobes.
279
- * Use reader/writer locks instead of plain spinlock.
280
- */
281
-static LIST_HEAD(break_hook);
282
-static DEFINE_SPINLOCK(break_hook_lock);
279
+static LIST_HEAD(user_break_hook);
280
+static LIST_HEAD(kernel_break_hook);
283281
284
-void register_break_hook(struct break_hook *hook)
282
+void register_user_break_hook(struct break_hook *hook)
285283 {
286
- spin_lock(&break_hook_lock);
287
- list_add_rcu(&hook->node, &break_hook);
288
- spin_unlock(&break_hook_lock);
284
+ register_debug_hook(&hook->node, &user_break_hook);
289285 }
290286
291
-void unregister_break_hook(struct break_hook *hook)
287
+void unregister_user_break_hook(struct break_hook *hook)
292288 {
293
- spin_lock(&break_hook_lock);
294
- list_del_rcu(&hook->node);
295
- spin_unlock(&break_hook_lock);
296
- synchronize_rcu();
289
+ unregister_debug_hook(&hook->node);
290
+}
291
+
292
+void register_kernel_break_hook(struct break_hook *hook)
293
+{
294
+ register_debug_hook(&hook->node, &kernel_break_hook);
295
+}
296
+EXPORT_SYMBOL_GPL(register_kernel_break_hook);
297
+
298
+void unregister_kernel_break_hook(struct break_hook *hook)
299
+{
300
+ unregister_debug_hook(&hook->node);
297301 }
298302
299303 static int call_break_hook(struct pt_regs *regs, unsigned int esr)
300304 {
301305 struct break_hook *hook;
306
+ struct list_head *list;
302307 int (*fn)(struct pt_regs *regs, unsigned int esr) = NULL;
303308
304
- rcu_read_lock();
305
- list_for_each_entry_rcu(hook, &break_hook, node)
306
- if ((esr & hook->esr_mask) == hook->esr_val)
309
+ list = user_mode(regs) ? &user_break_hook : &kernel_break_hook;
310
+
311
+ /*
312
+ * Since brk exception disables interrupt, this function is
313
+ * entirely not preemptible, and we can use rcu list safely here.
314
+ */
315
+ list_for_each_entry_rcu(hook, list, node) {
316
+ unsigned int comment = esr & ESR_ELx_BRK64_ISS_COMMENT_MASK;
317
+
318
+ if ((comment & ~hook->mask) == hook->imm)
307319 fn = hook->fn;
308
- rcu_read_unlock();
320
+ }
309321
310322 return fn ? fn(regs, esr) : DBG_HOOK_ERROR;
311323 }
312324 NOKPROBE_SYMBOL(call_break_hook);
313325
314
-static int brk_handler(unsigned long addr, unsigned int esr,
326
+static int brk_handler(unsigned long unused, unsigned int esr,
315327 struct pt_regs *regs)
316328 {
317
- bool handler_found = false;
329
+ if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED)
330
+ return 0;
318331
319
-#ifdef CONFIG_KPROBES
320
- if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) {
321
- if (kprobe_breakpoint_handler(regs, esr) == DBG_HOOK_HANDLED)
322
- handler_found = true;
323
- }
324
-#endif
325
- if (!handler_found && call_break_hook(regs, esr) == DBG_HOOK_HANDLED)
326
- handler_found = true;
327
-
328
- if (!handler_found && user_mode(regs)) {
332
+ if (user_mode(regs)) {
329333 send_user_sigtrap(TRAP_BRKPT);
330
- } else if (!handler_found) {
334
+ } else {
331335 pr_warn("Unexpected kernel BRK exception at EL1\n");
332336 return -EFAULT;
333337 }
....@@ -375,15 +379,13 @@
375379 }
376380 NOKPROBE_SYMBOL(aarch32_break_handler);
377381
378
-static int __init debug_traps_init(void)
382
+void __init debug_traps_init(void)
379383 {
380384 hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
381385 TRAP_TRACE, "single-step handler");
382386 hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,
383
- TRAP_BRKPT, "ptrace BRK handler");
384
- return 0;
387
+ TRAP_BRKPT, "BRK handler");
385388 }
386
-arch_initcall(debug_traps_init);
387389
388390 /* Re-enable single step for syscall restarting. */
389391 void user_rewind_single_step(struct task_struct *task)
....@@ -437,6 +439,11 @@
437439 }
438440 NOKPROBE_SYMBOL(kernel_active_single_step);
439441
442
+void kernel_rewind_single_step(struct pt_regs *regs)
443
+{
444
+ set_regs_spsr_ss(regs);
445
+}
446
+
440447 /* ptrace API */
441448 void user_enable_single_step(struct task_struct *task)
442449 {