12 #include <linux/kernel.h>
13 #include <linux/sched.h>
15 #include <linux/elf.h>
17 #include <linux/ptrace.h>
21 #include <linux/signal.h>
23 #include <linux/perf_event.h>
24 #include <linux/hw_breakpoint.h>
26 #include <linux/audit.h>
30 #include <asm/pgtable.h>
31 #include <asm/traps.h>
33 #define CREATE_TRACE_POINTS
47 #define BREAKINST_ARM 0xef9f0001
48 #define BREAKINST_THUMB 0xdf00
58 #define BREAKINST_ARM 0xe7f001f0
59 #define BREAKINST_THUMB 0xde01
67 #define REG_OFFSET_NAME(r) \
68 {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
69 #define REG_OFFSET_END {.name = NULL, .offset = 0}
103 for (roff = regoffset_table; roff->
name !=
NULL; roff++)
119 for (roff = regoffset_table; roff->
name !=
NULL; roff++)
120 if (roff->
offset == offset)
184 if (valid_user_regs(&newregs)) {
215 static int break_trap(
struct pt_regs *regs,
unsigned int instr)
222 .instr_mask = 0x0fffffff,
223 .instr_val = 0x07f001f0,
230 .instr_mask = 0xffff,
237 static struct undef_hook thumb2_break_hook = {
238 .instr_mask = 0xffffffff,
239 .instr_val = 0xf7f0a000,
245 static int __init ptrace_break_init(
void)
259 static int ptrace_read_user(
struct task_struct *tsk,
unsigned long off,
260 unsigned long __user *ret)
269 tmp = tsk->
mm->start_code;
271 tmp = tsk->
mm->start_data;
273 tmp = tsk->
mm->end_code;
274 else if (off <
sizeof(
struct pt_regs))
275 tmp = get_user_reg(tsk, off >> 2);
276 else if (off >=
sizeof(
struct user))
286 static int ptrace_write_user(
struct task_struct *tsk,
unsigned long off,
289 if (off & 3 || off >=
sizeof(
struct user))
292 if (off >=
sizeof(
struct pt_regs))
295 return put_user_reg(tsk, off >> 2, val);
303 static int ptrace_getwmmxregs(
struct task_struct *tsk,
void __user *
ufp)
307 if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
309 iwmmxt_task_disable(thread);
317 static int ptrace_setwmmxregs(
struct task_struct *tsk,
void __user *ufp)
321 if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
323 iwmmxt_task_release(thread);
334 static int ptrace_getcrunchregs(
struct task_struct *tsk,
void __user *ufp)
338 crunch_task_disable(thread);
346 static int ptrace_setcrunchregs(
struct task_struct *tsk,
void __user *ufp)
356 #ifdef CONFIG_HAVE_HW_BREAKPOINT
364 static int ptrace_hbp_num_to_idx(
long num)
367 num = (ARM_MAX_BRP << 1) - num;
368 return (num - 1) >> 1;
375 static long ptrace_hbp_idx_to_num(
int idx)
377 long mid = ARM_MAX_BRP << 1;
378 long num = (idx << 1) + 1;
379 return num > mid ? mid - num : num;
385 static void ptrace_hbptriggered(
struct perf_event *bp,
386 struct perf_sample_data *data,
394 for (i = 0; i < ARM_MAX_HBP_SLOTS; ++
i)
395 if (
current->thread.debug.hbp[i] == bp)
398 num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i);
403 info.si_addr = (
void __user *)(bkpt->trigger);
413 void clear_ptrace_hw_breakpoint(
struct task_struct *tsk)
427 for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) {
428 if (t->debug.hbp[i]) {
430 t->debug.hbp[
i] =
NULL;
435 static u32 ptrace_get_hbp_resource_info(
void)
437 u8 num_brps, num_wrps, debug_arch, wp_len;
460 ptrace_breakpoint_init(&
attr);
472 static int ptrace_gethbpregs(
struct task_struct *tsk,
long num,
473 unsigned long __user *data)
478 struct arch_hw_breakpoint_ctrl arch_ctrl;
481 reg = ptrace_get_hbp_resource_info();
483 idx = ptrace_hbp_num_to_idx(num);
484 if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
495 arch_ctrl = counter_arch_bp(bp)->ctrl;
501 while (!(arch_ctrl.len & 0x1))
505 reg = bp->
attr.bp_addr;
507 reg = encode_ctrl_reg(arch_ctrl);
518 static int ptrace_sethbpregs(
struct task_struct *tsk,
long num,
519 unsigned long __user *data)
521 int idx, gen_len, gen_type, implied_type, ret = 0;
524 struct arch_hw_breakpoint_ctrl
ctrl;
534 idx = ptrace_hbp_num_to_idx(num);
535 if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
547 bp = ptrace_hbp_create(tsk, implied_type);
559 attr.bp_addr = user_val;
562 decode_ctrl_reg(user_val, &
ctrl);
567 if ((gen_type & implied_type) != gen_type) {
572 attr.bp_len = gen_len;
573 attr.bp_type = gen_type;
587 unsigned int pos,
unsigned int count,
588 void *kbuf,
void __user *ubuf)
592 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
599 unsigned int pos,
unsigned int count,
600 const void *kbuf,
const void __user *ubuf)
605 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
611 if (!valid_user_regs(&newregs))
620 unsigned int pos,
unsigned int count,
621 void *kbuf,
void __user *ubuf)
623 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
630 unsigned int pos,
unsigned int count,
631 const void *kbuf,
const void __user *ubuf)
635 thread->used_cp[1] = thread->used_cp[2] = 1;
637 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
667 unsigned int pos,
unsigned int count,
668 void *kbuf,
void __user *ubuf)
678 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
681 user_fpregs_offset +
sizeof(vfp->
fpregs));
685 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
686 user_fpregs_offset +
sizeof(vfp->
fpregs),
691 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
694 user_fpscr_offset +
sizeof(vfp->
fpscr));
704 unsigned int pos,
unsigned int count,
705 const void *kbuf,
const void __user *ubuf)
714 new_vfp = thread->vfpstate.hard;
716 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
719 user_fpregs_offset +
sizeof(new_vfp.fpregs));
723 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
724 user_fpregs_offset +
sizeof(new_vfp.fpregs),
729 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
732 user_fpscr_offset +
sizeof(new_vfp.fpscr));
737 thread->vfpstate.hard = new_vfp;
781 .align =
sizeof(
u32),
790 .regsets = arm_regsets, .
n =
ARRAY_SIZE(arm_regsets)
795 return &user_arm_view;
799 unsigned long addr,
unsigned long data)
802 unsigned long __user *datap = (
unsigned long __user *) data;
806 ret = ptrace_read_user(child, addr, datap);
810 ret = ptrace_write_user(child, addr, data);
814 ret = copy_regset_to_user(child,
821 ret = copy_regset_from_user(child,
828 ret = copy_regset_to_user(child,
835 ret = copy_regset_from_user(child,
843 ret = ptrace_getwmmxregs(child, datap);
847 ret = ptrace_setwmmxregs(child, datap);
863 ret = ptrace_getcrunchregs(child, datap);
867 ret = ptrace_setcrunchregs(child, datap);
873 ret = copy_regset_to_user(child,
874 &user_arm_view, REGSET_VFP,
880 ret = copy_regset_from_user(child,
881 &user_arm_view, REGSET_VFP,
887 #ifdef CONFIG_HAVE_HW_BREAKPOINT
889 if (ptrace_get_breakpoints(child) < 0)
892 ret = ptrace_gethbpregs(child, addr,
893 (
unsigned long __user *)data);
894 ptrace_put_breakpoints(child);
897 if (ptrace_get_breakpoints(child) < 0)
900 ret = ptrace_sethbpregs(child, addr,
901 (
unsigned long __user *)data);
902 ptrace_put_breakpoints(child);
919 static int ptrace_syscall_trace(
struct pt_regs *regs,
int scno,
937 tracehook_report_syscall_exit(regs, 0);
938 else if (tracehook_report_syscall_entry(regs))
949 trace_sys_enter(regs, scno);
950 audit_syscall_entry(
AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
951 regs->ARM_r2, regs->ARM_r3);
959 trace_sys_exit(regs, scno);
960 audit_syscall_exit(regs);