aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2013-03-16 04:48:13 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2013-06-12 06:23:02 -0400
commit1442b6ed249d2b3d2cfcf45b65ac64393495c96c (patch)
tree440be3115d6d3ac4aa766c295d9b15c8160da38f
parentadace89562c7a9645b8dc84f6e1ac7ba8756094e (diff)
arm64: debug: consolidate software breakpoint handlers
The software breakpoint handlers are hooked in directly from ptrace, which makes it difficult to add additional handlers for things like kprobes and kgdb. This patch moves the handling code into debug-monitors.c, where we can dispatch to different debug subsystems more easily. Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm64/include/asm/debug-monitors.h9
-rw-r--r--arch/arm64/include/asm/ptrace.h2
-rw-r--r--arch/arm64/kernel/debug-monitors.c66
-rw-r--r--arch/arm64/kernel/ptrace.c59
-rw-r--r--arch/arm64/kernel/traps.c5
5 files changed, 75 insertions, 66 deletions
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 7eaa0b302493..ef8235c68c09 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -83,6 +83,15 @@ static inline int reinstall_suspended_bps(struct pt_regs *regs)
83} 83}
84#endif 84#endif
85 85
86#ifdef CONFIG_COMPAT
87int aarch32_break_handler(struct pt_regs *regs);
88#else
89static int aarch32_break_handler(struct pt_regs *regs)
90{
91 return -EFAULT;
92}
93#endif
94
86#endif /* __ASSEMBLY */ 95#endif /* __ASSEMBLY */
87#endif /* __KERNEL__ */ 96#endif /* __KERNEL__ */
88#endif /* __ASM_DEBUG_MONITORS_H */ 97#endif /* __ASM_DEBUG_MONITORS_H */
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 41a71ee4c3df..0dacbbf9458b 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -171,7 +171,5 @@ extern unsigned long profile_pc(struct pt_regs *regs);
171#define profile_pc(regs) instruction_pointer(regs) 171#define profile_pc(regs) instruction_pointer(regs)
172#endif 172#endif
173 173
174extern int aarch32_break_trap(struct pt_regs *regs);
175
176#endif /* __ASSEMBLY__ */ 174#endif /* __ASSEMBLY__ */
177#endif 175#endif
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index f4726dc054b3..08018e3df580 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -24,6 +24,7 @@
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/ptrace.h> 25#include <linux/ptrace.h>
26#include <linux/stat.h> 26#include <linux/stat.h>
27#include <linux/uaccess.h>
27 28
28#include <asm/debug-monitors.h> 29#include <asm/debug-monitors.h>
29#include <asm/local.h> 30#include <asm/local.h>
@@ -226,13 +227,74 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
226 return 0; 227 return 0;
227} 228}
228 229
229static int __init single_step_init(void) 230static int brk_handler(unsigned long addr, unsigned int esr,
231 struct pt_regs *regs)
232{
233 siginfo_t info;
234
235 if (!user_mode(regs))
236 return -EFAULT;
237
238 info = (siginfo_t) {
239 .si_signo = SIGTRAP,
240 .si_errno = 0,
241 .si_code = TRAP_BRKPT,
242 .si_addr = (void __user *)instruction_pointer(regs),
243 };
244
245 force_sig_info(SIGTRAP, &info, current);
246 return 0;
247}
248
249int aarch32_break_handler(struct pt_regs *regs)
250{
251 siginfo_t info;
252 unsigned int instr;
253 bool bp = false;
254 void __user *pc = (void __user *)instruction_pointer(regs);
255
256 if (!compat_user_mode(regs))
257 return -EFAULT;
258
259 if (compat_thumb_mode(regs)) {
260 /* get 16-bit Thumb instruction */
261 get_user(instr, (u16 __user *)pc);
262 if (instr == AARCH32_BREAK_THUMB2_LO) {
263 /* get second half of 32-bit Thumb-2 instruction */
264 get_user(instr, (u16 __user *)(pc + 2));
265 bp = instr == AARCH32_BREAK_THUMB2_HI;
266 } else {
267 bp = instr == AARCH32_BREAK_THUMB;
268 }
269 } else {
270 /* 32-bit ARM instruction */
271 get_user(instr, (u32 __user *)pc);
272 bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
273 }
274
275 if (!bp)
276 return -EFAULT;
277
278 info = (siginfo_t) {
279 .si_signo = SIGTRAP,
280 .si_errno = 0,
281 .si_code = TRAP_BRKPT,
282 .si_addr = pc,
283 };
284
285 force_sig_info(SIGTRAP, &info, current);
286 return 0;
287}
288
289static int __init debug_traps_init(void)
230{ 290{
231 hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP, 291 hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
232 TRAP_HWBKPT, "single-step handler"); 292 TRAP_HWBKPT, "single-step handler");
293 hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,
294 TRAP_BRKPT, "ptrace BRK handler");
233 return 0; 295 return 0;
234} 296}
235arch_initcall(single_step_init); 297arch_initcall(debug_traps_init);
236 298
237/* Re-enable single step for syscall restarting. */ 299/* Re-enable single step for syscall restarting. */
238void user_rewind_single_step(struct task_struct *task) 300void user_rewind_single_step(struct task_struct *task)
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 6e1e77f1831c..fecdbf7de82e 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -53,28 +53,6 @@ void ptrace_disable(struct task_struct *child)
53{ 53{
54} 54}
55 55
56/*
57 * Handle hitting a breakpoint.
58 */
59static int ptrace_break(struct pt_regs *regs)
60{
61 siginfo_t info = {
62 .si_signo = SIGTRAP,
63 .si_errno = 0,
64 .si_code = TRAP_BRKPT,
65 .si_addr = (void __user *)instruction_pointer(regs),
66 };
67
68 force_sig_info(SIGTRAP, &info, current);
69 return 0;
70}
71
72static int arm64_break_trap(unsigned long addr, unsigned int esr,
73 struct pt_regs *regs)
74{
75 return ptrace_break(regs);
76}
77
78#ifdef CONFIG_HAVE_HW_BREAKPOINT 56#ifdef CONFIG_HAVE_HW_BREAKPOINT
79/* 57/*
80 * Handle hitting a HW-breakpoint. 58 * Handle hitting a HW-breakpoint.
@@ -817,33 +795,6 @@ static const struct user_regset_view user_aarch32_view = {
817 .regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets) 795 .regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
818}; 796};
819 797
820int aarch32_break_trap(struct pt_regs *regs)
821{
822 unsigned int instr;
823 bool bp = false;
824 void __user *pc = (void __user *)instruction_pointer(regs);
825
826 if (compat_thumb_mode(regs)) {
827 /* get 16-bit Thumb instruction */
828 get_user(instr, (u16 __user *)pc);
829 if (instr == AARCH32_BREAK_THUMB2_LO) {
830 /* get second half of 32-bit Thumb-2 instruction */
831 get_user(instr, (u16 __user *)(pc + 2));
832 bp = instr == AARCH32_BREAK_THUMB2_HI;
833 } else {
834 bp = instr == AARCH32_BREAK_THUMB;
835 }
836 } else {
837 /* 32-bit ARM instruction */
838 get_user(instr, (u32 __user *)pc);
839 bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
840 }
841
842 if (bp)
843 return ptrace_break(regs);
844 return 1;
845}
846
847static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, 798static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
848 compat_ulong_t __user *ret) 799 compat_ulong_t __user *ret)
849{ 800{
@@ -1111,16 +1062,6 @@ long arch_ptrace(struct task_struct *child, long request,
1111 return ptrace_request(child, request, addr, data); 1062 return ptrace_request(child, request, addr, data);
1112} 1063}
1113 1064
1114
1115static int __init ptrace_break_init(void)
1116{
1117 hook_debug_fault_code(DBG_ESR_EVT_BRK, arm64_break_trap, SIGTRAP,
1118 TRAP_BRKPT, "ptrace BRK handler");
1119 return 0;
1120}
1121core_initcall(ptrace_break_init);
1122
1123
1124asmlinkage int syscall_trace(int dir, struct pt_regs *regs) 1065asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
1125{ 1066{
1126 unsigned long saved_reg; 1067 unsigned long saved_reg;
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index f30852d28590..7ffadddb645d 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -32,6 +32,7 @@
32#include <linux/syscalls.h> 32#include <linux/syscalls.h>
33 33
34#include <asm/atomic.h> 34#include <asm/atomic.h>
35#include <asm/debug-monitors.h>
35#include <asm/traps.h> 36#include <asm/traps.h>
36#include <asm/stacktrace.h> 37#include <asm/stacktrace.h>
37#include <asm/exception.h> 38#include <asm/exception.h>
@@ -261,11 +262,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
261 siginfo_t info; 262 siginfo_t info;
262 void __user *pc = (void __user *)instruction_pointer(regs); 263 void __user *pc = (void __user *)instruction_pointer(regs);
263 264
264#ifdef CONFIG_COMPAT
265 /* check for AArch32 breakpoint instructions */ 265 /* check for AArch32 breakpoint instructions */
266 if (compat_user_mode(regs) && aarch32_break_trap(regs) == 0) 266 if (!aarch32_break_handler(regs))
267 return; 267 return;
268#endif
269 268
270 if (show_unhandled_signals && unhandled_signal(current, SIGILL) && 269 if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
271 printk_ratelimit()) { 270 printk_ratelimit()) {