22 #include <linux/kernel.h>
23 #include <linux/sched.h>
26 #include <linux/ptrace.h>
30 #include <linux/signal.h>
32 #include <linux/perf_event.h>
33 #include <linux/hw_breakpoint.h>
36 #include <linux/elf.h>
38 #include <asm/compat.h>
40 #include <asm/pgtable.h>
41 #include <asm/traps.h>
42 #include <asm/system_misc.h>
72 static int arm64_break_trap(
unsigned long addr,
unsigned int esr,
78 #ifdef CONFIG_HAVE_HW_BREAKPOINT
82 static void ptrace_hbptriggered(
struct perf_event *bp,
83 struct perf_sample_data *
data,
91 .si_addr = (
void __user *)(bkpt->trigger),
100 for (i = 0; i < ARM_MAX_BRP; ++
i) {
101 if (
current->thread.debug.hbp_break[i] == bp) {
106 for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++
i) {
107 if (
current->thread.debug.hbp_watch[i] == bp) {
127 for (i = 0; i < ARM_MAX_BRP; i++) {
128 if (t->debug.hbp_break[i]) {
130 t->debug.hbp_break[
i] =
NULL;
134 for (i = 0; i < ARM_MAX_WRP; i++) {
135 if (t->debug.hbp_watch[i]) {
137 t->debug.hbp_watch[
i] =
NULL;
142 void ptrace_hw_copy_thread(
struct task_struct *tsk)
147 static struct perf_event *ptrace_hbp_get_event(
unsigned int note_type,
155 if (idx < ARM_MAX_BRP)
159 if (idx < ARM_MAX_WRP)
167 static int ptrace_hbp_set_event(
unsigned int note_type,
176 if (idx < ARM_MAX_BRP) {
182 if (idx < ARM_MAX_WRP) {
192 static struct perf_event *ptrace_hbp_create(
unsigned int note_type,
211 ptrace_breakpoint_init(&
attr);
226 err = ptrace_hbp_set_event(note_type, tsk, idx, bp);
233 static int ptrace_hbp_fill_attr_ctrl(
unsigned int note_type,
234 struct arch_hw_breakpoint_ctrl
ctrl,
268 static int ptrace_hbp_get_resource_info(
unsigned int note_type,
u32 *info)
292 static int ptrace_hbp_get_ctrl(
unsigned int note_type,
297 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
302 *ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0;
306 static int ptrace_hbp_get_addr(
unsigned int note_type,
311 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
316 *addr = bp ? bp->
attr.bp_addr : 0;
320 static struct perf_event *ptrace_hbp_get_initialised_bp(
unsigned int note_type,
324 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
327 bp = ptrace_hbp_create(note_type, tsk, idx);
332 static int ptrace_hbp_set_ctrl(
unsigned int note_type,
340 struct arch_hw_breakpoint_ctrl ctrl;
342 bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
349 decode_ctrl_reg(uctrl, &ctrl);
350 err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
357 static int ptrace_hbp_set_addr(
unsigned int note_type,
366 bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
378 #define PTRACE_HBP_ADDR_SZ sizeof(u64)
379 #define PTRACE_HBP_CTRL_SZ sizeof(u32)
380 #define PTRACE_HBP_PAD_SZ sizeof(u32)
384 unsigned int pos,
unsigned int count,
385 void *kbuf,
void __user *ubuf)
393 ret = ptrace_hbp_get_resource_info(note_type, &info);
397 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0,
404 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
offset,
405 offset + PTRACE_HBP_PAD_SZ);
411 limit = regset->
n * regset->
size;
412 while (count &&
offset < limit) {
413 ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
416 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr,
420 offset += PTRACE_HBP_ADDR_SZ;
422 ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
425 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl,
429 offset += PTRACE_HBP_CTRL_SZ;
431 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
433 offset + PTRACE_HBP_PAD_SZ);
436 offset += PTRACE_HBP_PAD_SZ;
443 static int hw_break_set(
struct task_struct *target,
445 unsigned int pos,
unsigned int count,
446 const void *kbuf,
const void __user *ubuf)
455 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0,
offset);
460 limit = regset->
n * regset->
size;
461 while (count &&
offset < limit) {
462 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
466 ret = ptrace_hbp_set_addr(note_type, target, idx, addr);
469 offset += PTRACE_HBP_ADDR_SZ;
471 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
475 ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl);
478 offset += PTRACE_HBP_CTRL_SZ;
480 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
482 offset + PTRACE_HBP_PAD_SZ);
485 offset += PTRACE_HBP_PAD_SZ;
495 unsigned int pos,
unsigned int count,
496 void *kbuf,
void __user *ubuf)
499 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
503 unsigned int pos,
unsigned int count,
504 const void *kbuf,
const void __user *ubuf)
509 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
513 if (!valid_user_regs(&newregs))
524 unsigned int pos,
unsigned int count,
525 void *kbuf,
void __user *ubuf)
528 uregs = &target->
thread.fpsimd_state.user_fpsimd;
529 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
533 unsigned int pos,
unsigned int count,
534 const void *kbuf,
const void __user *ubuf)
539 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
543 target->
thread.fpsimd_state.user_fpsimd = newstate;
548 unsigned int pos,
unsigned int count,
549 void *kbuf,
void __user *ubuf)
551 unsigned long *tls = &target->
thread.tp_value;
552 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1);
556 unsigned int pos,
unsigned int count,
557 const void *kbuf,
const void __user *ubuf)
562 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
566 target->
thread.tp_value = tls;
574 #ifdef CONFIG_HAVE_HW_BREAKPOINT
580 static const struct user_regset aarch64_regsets[] = {
585 .
align =
sizeof(u64),
604 .size =
sizeof(
void *),
605 .
align =
sizeof(
void *),
609 #ifdef CONFIG_HAVE_HW_BREAKPOINT
610 [REGSET_HW_BREAK] = {
618 [REGSET_HW_WATCH] = {
631 .regsets = aarch64_regsets, .
n =
ARRAY_SIZE(aarch64_regsets)
642 static int compat_gpr_get(
struct task_struct *target,
644 unsigned int pos,
unsigned int count,
645 void *kbuf,
void __user *ubuf)
648 unsigned int i,
start, num_regs;
651 num_regs = count / regset->
size;
654 start = pos / regset->
size;
656 if (start + num_regs > regset->
n)
659 for (i = 0; i < num_regs; ++
i) {
660 unsigned int idx = start +
i;
688 static int compat_gpr_set(
struct task_struct *target,
690 unsigned int pos,
unsigned int count,
691 const void *kbuf,
const void __user *ubuf)
695 unsigned int i,
start, num_regs;
698 num_regs = count / regset->
size;
701 start = pos / regset->
size;
703 if (start + num_regs > regset->
n)
708 for (i = 0; i < num_regs; ++
i) {
709 unsigned int idx = start +
i;
714 reg = (
void *)&newregs.pc;
717 reg = (
void *)&newregs.pstate;
720 reg = (
void *)&newregs.orig_x0;
723 reg = (
void *)&newregs.regs[
idx];
734 if (valid_user_regs(&newregs.user_regs))
743 static int compat_vfp_get(
struct task_struct *target,
745 unsigned int pos,
unsigned int count,
746 void *kbuf,
void __user *ubuf)
752 uregs = &target->
thread.fpsimd_state.user_fpsimd;
758 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
762 fpscr = (uregs->
fpsr & VFP_FPSCR_STAT_MASK) |
763 (uregs->
fpcr & VFP_FPSCR_CTRL_MASK);
770 static int compat_vfp_set(
struct task_struct *target,
772 unsigned int pos,
unsigned int count,
773 const void *kbuf,
const void __user *ubuf)
779 if (pos + count > VFP_STATE_SIZE)
782 uregs = &target->
thread.fpsimd_state.user_fpsimd;
784 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
789 uregs->
fpsr = fpscr & VFP_FPSCR_STAT_MASK;
790 uregs->
fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
796 static const struct user_regset aarch32_regsets[] = {
797 [REGSET_COMPAT_GPR] = {
802 .get = compat_gpr_get,
803 .set = compat_gpr_set
805 [REGSET_COMPAT_VFP] = {
810 .
get = compat_vfp_get,
811 .
set = compat_vfp_set
817 .regsets = aarch32_regsets, .
n =
ARRAY_SIZE(aarch32_regsets)
829 if (instr == AARCH32_BREAK_THUMB2_LO) {
832 bp = instr == AARCH32_BREAK_THUMB2_HI;
834 bp = instr == AARCH32_BREAK_THUMB;
839 bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
856 tmp = tsk->
mm->start_code;
858 tmp = tsk->
mm->start_data;
860 tmp = tsk->
mm->end_code;
862 return copy_regset_to_user(tsk, &user_aarch32_view,
863 REGSET_COMPAT_GPR, off,
884 ret = copy_regset_from_user(tsk, &user_aarch32_view,
885 REGSET_COMPAT_GPR, off,
891 #ifdef CONFIG_HAVE_HW_BREAKPOINT
902 return (
abs(num) - 1) >> 1;
905 static int compat_ptrace_hbp_get_resource_info(
u32 *kdata)
907 u8 num_brps, num_wrps, debug_arch, wp_len;
927 static int compat_ptrace_hbp_get(
unsigned int note_type,
935 int err, idx = compat_ptrace_hbp_num_to_idx(num);;
938 err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr);
941 err = ptrace_hbp_get_ctrl(note_type, tsk, idx, &ctrl);
948 static int compat_ptrace_hbp_set(
unsigned int note_type,
956 int err, idx = compat_ptrace_hbp_num_to_idx(num);
960 err = ptrace_hbp_set_addr(note_type, tsk, idx, addr);
963 err = ptrace_hbp_set_ctrl(note_type, tsk, idx, ctrl);
981 }
else if (num == 0) {
982 ret = compat_ptrace_hbp_get_resource_info(&kdata);
1023 unsigned long addr = caddr;
1024 unsigned long data =
cdata;
1025 void __user *datap = compat_ptr(data);
1030 ret = compat_ptrace_read_user(child, addr, datap);
1034 ret = compat_ptrace_write_user(child, addr, data);
1038 ret = copy_regset_to_user(child,
1046 ret = copy_regset_from_user(child,
1064 ret = copy_regset_to_user(child,
1072 ret = copy_regset_from_user(child,
1079 #ifdef CONFIG_HAVE_HW_BREAKPOINT
1081 ret = compat_ptrace_gethbpregs(child, addr, datap);
1085 ret = compat_ptrace_sethbpregs(child, addr, datap);
1090 ret = compat_ptrace_request(child, request, addr,
1101 #ifdef CONFIG_COMPAT
1103 return &user_aarch32_view;
1105 return &user_aarch64_view;
1109 unsigned long addr,
unsigned long data)
1115 static int __init ptrace_break_init(
void)
1126 unsigned long saved_reg;
1133 saved_reg = regs->
regs[12];
1134 regs->
regs[12] = dir;
1140 saved_reg = regs->
regs[7];
1141 regs->
regs[7] = dir;
1145 tracehook_report_syscall_exit(regs, 0);
1146 else if (tracehook_report_syscall_entry(regs))
1150 regs->
regs[12] = saved_reg;
1152 regs->
regs[7] = saved_reg;