Loading arch/Kconfig +11 −0 Original line number Original line Diff line number Diff line Loading @@ -137,6 +137,17 @@ config HAVE_HW_BREAKPOINT bool bool depends on PERF_EVENTS depends on PERF_EVENTS config HAVE_MIXED_BREAKPOINTS_REGS bool depends on HAVE_HW_BREAKPOINT help Depending on the arch implementation of hardware breakpoints, some of them have separate registers for data and instruction breakpoints addresses, others have mixed registers to store them but define the access type in a control register. Select this option if your arch implements breakpoints under the latter fashion. config HAVE_USER_RETURN_NOTIFIER config HAVE_USER_RETURN_NOTIFIER bool bool Loading arch/sh/Kconfig +1 −0 Original line number Original line Diff line number Diff line Loading @@ -44,6 +44,7 @@ config SUPERH32 select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB select HAVE_HW_BREAKPOINT select HAVE_HW_BREAKPOINT select HAVE_MIXED_BREAKPOINTS_REGS select PERF_EVENTS if HAVE_HW_BREAKPOINT select PERF_EVENTS if HAVE_HW_BREAKPOINT select ARCH_HIBERNATION_POSSIBLE if MMU select ARCH_HIBERNATION_POSSIBLE if MMU Loading arch/sh/include/asm/hw_breakpoint.h +7 −3 Original line number Original line Diff line number Diff line Loading @@ -46,10 +46,14 @@ struct pmu; /* Maximum number of UBC channels */ /* Maximum number of UBC channels */ #define HBP_NUM 2 #define HBP_NUM 2 static inline int hw_breakpoint_slots(int type) { return HBP_NUM; } /* arch/sh/kernel/hw_breakpoint.c */ /* arch/sh/kernel/hw_breakpoint.c */ extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len); extern int arch_check_bp_in_kernelspace(struct perf_event *bp); extern int arch_validate_hwbkpt_settings(struct perf_event *bp, extern int arch_validate_hwbkpt_settings(struct perf_event *bp); struct task_struct *tsk); extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, unsigned long val, void *data); unsigned long val, void *data); Loading arch/sh/kernel/hw_breakpoint.c +7 −27 Original line number Original line Diff line number Diff line Loading @@ -119,26 +119,17 @@ static int get_hbp_len(u16 hbp_len) return len_in_bytes; return len_in_bytes; } } /* * Check for virtual address in user space. */ int arch_check_va_in_userspace(unsigned long va, u16 hbp_len) { unsigned int len; len = get_hbp_len(hbp_len); return (va <= TASK_SIZE - len); } /* /* * Check for virtual address in kernel space. * Check for virtual address in kernel space. */ */ static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len) int arch_check_bp_in_kernelspace(struct perf_event *bp) { { unsigned int len; unsigned int len; unsigned long va; struct arch_hw_breakpoint *info = counter_arch_bp(bp); len = get_hbp_len(hbp_len); va = info->address; len = get_hbp_len(info->len); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); } } Loading Loading @@ -226,8 +217,7 @@ static int arch_build_bp_info(struct perf_event *bp) /* /* * Validate the arch-specific HW Breakpoint register settings * Validate the arch-specific HW Breakpoint register settings */ */ int arch_validate_hwbkpt_settings(struct perf_event *bp, int arch_validate_hwbkpt_settings(struct perf_event *bp) struct task_struct *tsk) { { struct arch_hw_breakpoint *info = counter_arch_bp(bp); struct arch_hw_breakpoint *info = counter_arch_bp(bp); unsigned int align; unsigned int align; Loading Loading @@ -270,15 +260,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, if (info->address & align) if (info->address & align) return -EINVAL; return -EINVAL; /* Check that the virtual address is in the proper range */ if (tsk) { if (!arch_check_va_in_userspace(info->address, info->len)) return -EFAULT; } else { if (!arch_check_va_in_kernelspace(info->address, info->len)) return -EFAULT; } return 0; return 0; } } Loading Loading @@ -363,8 +344,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) perf_bp_event(bp, args->regs); perf_bp_event(bp, args->regs); /* Deliver the signal to userspace */ /* Deliver the signal to userspace */ if (arch_check_va_in_userspace(bp->attr.bp_addr, if (!arch_check_bp_in_kernelspace(bp)) { bp->attr.bp_len)) { siginfo_t info; siginfo_t info; info.si_signo = args->signr; info.si_signo = args->signr; Loading arch/sh/kernel/ptrace_32.c +1 −1 Original line number Original line Diff line number Diff line Loading @@ -85,7 +85,7 @@ static int set_single_step(struct task_struct *tsk, unsigned long addr) bp = thread->ptrace_bps[0]; bp = thread->ptrace_bps[0]; if (!bp) { if (!bp) { hw_breakpoint_init(&attr); ptrace_breakpoint_init(&attr); attr.bp_addr = addr; attr.bp_addr = addr; attr.bp_len = HW_BREAKPOINT_LEN_2; attr.bp_len = HW_BREAKPOINT_LEN_2; Loading Loading
arch/Kconfig +11 −0 Original line number Original line Diff line number Diff line Loading @@ -137,6 +137,17 @@ config HAVE_HW_BREAKPOINT bool bool depends on PERF_EVENTS depends on PERF_EVENTS config HAVE_MIXED_BREAKPOINTS_REGS bool depends on HAVE_HW_BREAKPOINT help Depending on the arch implementation of hardware breakpoints, some of them have separate registers for data and instruction breakpoints addresses, others have mixed registers to store them but define the access type in a control register. Select this option if your arch implements breakpoints under the latter fashion. config HAVE_USER_RETURN_NOTIFIER config HAVE_USER_RETURN_NOTIFIER bool bool Loading
arch/sh/Kconfig +1 −0 Original line number Original line Diff line number Diff line Loading @@ -44,6 +44,7 @@ config SUPERH32 select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB select HAVE_HW_BREAKPOINT select HAVE_HW_BREAKPOINT select HAVE_MIXED_BREAKPOINTS_REGS select PERF_EVENTS if HAVE_HW_BREAKPOINT select PERF_EVENTS if HAVE_HW_BREAKPOINT select ARCH_HIBERNATION_POSSIBLE if MMU select ARCH_HIBERNATION_POSSIBLE if MMU Loading
arch/sh/include/asm/hw_breakpoint.h +7 −3 Original line number Original line Diff line number Diff line Loading @@ -46,10 +46,14 @@ struct pmu; /* Maximum number of UBC channels */ /* Maximum number of UBC channels */ #define HBP_NUM 2 #define HBP_NUM 2 static inline int hw_breakpoint_slots(int type) { return HBP_NUM; } /* arch/sh/kernel/hw_breakpoint.c */ /* arch/sh/kernel/hw_breakpoint.c */ extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len); extern int arch_check_bp_in_kernelspace(struct perf_event *bp); extern int arch_validate_hwbkpt_settings(struct perf_event *bp, extern int arch_validate_hwbkpt_settings(struct perf_event *bp); struct task_struct *tsk); extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, unsigned long val, void *data); unsigned long val, void *data); Loading
arch/sh/kernel/hw_breakpoint.c +7 −27 Original line number Original line Diff line number Diff line Loading @@ -119,26 +119,17 @@ static int get_hbp_len(u16 hbp_len) return len_in_bytes; return len_in_bytes; } } /* * Check for virtual address in user space. */ int arch_check_va_in_userspace(unsigned long va, u16 hbp_len) { unsigned int len; len = get_hbp_len(hbp_len); return (va <= TASK_SIZE - len); } /* /* * Check for virtual address in kernel space. * Check for virtual address in kernel space. */ */ static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len) int arch_check_bp_in_kernelspace(struct perf_event *bp) { { unsigned int len; unsigned int len; unsigned long va; struct arch_hw_breakpoint *info = counter_arch_bp(bp); len = get_hbp_len(hbp_len); va = info->address; len = get_hbp_len(info->len); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); } } Loading Loading @@ -226,8 +217,7 @@ static int arch_build_bp_info(struct perf_event *bp) /* /* * Validate the arch-specific HW Breakpoint register settings * Validate the arch-specific HW Breakpoint register settings */ */ int arch_validate_hwbkpt_settings(struct perf_event *bp, int arch_validate_hwbkpt_settings(struct perf_event *bp) struct task_struct *tsk) { { struct arch_hw_breakpoint *info = counter_arch_bp(bp); struct arch_hw_breakpoint *info = counter_arch_bp(bp); unsigned int align; unsigned int align; Loading Loading @@ -270,15 +260,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, if (info->address & align) if (info->address & align) return -EINVAL; return -EINVAL; /* Check that the virtual address is in the proper range */ if (tsk) { if (!arch_check_va_in_userspace(info->address, info->len)) return -EFAULT; } else { if (!arch_check_va_in_kernelspace(info->address, info->len)) return -EFAULT; } return 0; return 0; } } Loading Loading @@ -363,8 +344,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) perf_bp_event(bp, args->regs); perf_bp_event(bp, args->regs); /* Deliver the signal to userspace */ /* Deliver the signal to userspace */ if (arch_check_va_in_userspace(bp->attr.bp_addr, if (!arch_check_bp_in_kernelspace(bp)) { bp->attr.bp_len)) { siginfo_t info; siginfo_t info; info.si_signo = args->signr; info.si_signo = args->signr; Loading
arch/sh/kernel/ptrace_32.c +1 −1 Original line number Original line Diff line number Diff line Loading @@ -85,7 +85,7 @@ static int set_single_step(struct task_struct *tsk, unsigned long addr) bp = thread->ptrace_bps[0]; bp = thread->ptrace_bps[0]; if (!bp) { if (!bp) { hw_breakpoint_init(&attr); ptrace_breakpoint_init(&attr); attr.bp_addr = addr; attr.bp_addr = addr; attr.bp_len = HW_BREAKPOINT_LEN_2; attr.bp_len = HW_BREAKPOINT_LEN_2; Loading