diff options
Diffstat (limited to 'arch/tile/kernel/ptrace.c')
-rw-r--r-- | arch/tile/kernel/ptrace.c | 108 |
1 files changed, 54 insertions, 54 deletions
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index 7161bd03d2fd..e92e40527d6d 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c | |||
@@ -32,25 +32,6 @@ void user_disable_single_step(struct task_struct *child) | |||
32 | } | 32 | } |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * This routine will put a word on the process's privileged stack. | ||
36 | */ | ||
37 | static void putreg(struct task_struct *task, | ||
38 | unsigned long addr, unsigned long value) | ||
39 | { | ||
40 | unsigned int regno = addr / sizeof(unsigned long); | ||
41 | struct pt_regs *childregs = task_pt_regs(task); | ||
42 | childregs->regs[regno] = value; | ||
43 | childregs->flags |= PT_FLAGS_RESTORE_REGS; | ||
44 | } | ||
45 | |||
46 | static unsigned long getreg(struct task_struct *task, unsigned long addr) | ||
47 | { | ||
48 | unsigned int regno = addr / sizeof(unsigned long); | ||
49 | struct pt_regs *childregs = task_pt_regs(task); | ||
50 | return childregs->regs[regno]; | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Called by kernel/ptrace.c when detaching.. | 35 | * Called by kernel/ptrace.c when detaching.. |
55 | */ | 36 | */ |
56 | void ptrace_disable(struct task_struct *child) | 37 | void ptrace_disable(struct task_struct *child) |
@@ -64,61 +45,80 @@ void ptrace_disable(struct task_struct *child) | |||
64 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 45 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
65 | } | 46 | } |
66 | 47 | ||
67 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 48 | long arch_ptrace(struct task_struct *child, long request, |
49 | unsigned long addr, unsigned long data) | ||
68 | { | 50 | { |
69 | unsigned long __user *datap; | 51 | unsigned long __user *datap = (long __user __force *)data; |
70 | unsigned long tmp; | 52 | unsigned long tmp; |
71 | int i; | ||
72 | long ret = -EIO; | 53 | long ret = -EIO; |
73 | 54 | char *childreg; | |
74 | #ifdef CONFIG_COMPAT | 55 | struct pt_regs copyregs; |
75 | if (task_thread_info(current)->status & TS_COMPAT) | 56 | int ex1_offset; |
76 | data = (u32)data; | ||
77 | if (task_thread_info(child)->status & TS_COMPAT) | ||
78 | addr = (u32)addr; | ||
79 | #endif | ||
80 | datap = (unsigned long __user __force *)data; | ||
81 | 57 | ||
82 | switch (request) { | 58 | switch (request) { |
83 | 59 | ||
84 | case PTRACE_PEEKUSR: /* Read register from pt_regs. */ | 60 | case PTRACE_PEEKUSR: /* Read register from pt_regs. */ |
85 | if (addr & (sizeof(data)-1)) | 61 | if (addr >= PTREGS_SIZE) |
86 | break; | ||
87 | if (addr < 0 || addr >= PTREGS_SIZE) | ||
88 | break; | 62 | break; |
89 | tmp = getreg(child, addr); /* Read register */ | 63 | childreg = (char *)task_pt_regs(child) + addr; |
90 | ret = put_user(tmp, datap); | 64 | #ifdef CONFIG_COMPAT |
65 | if (is_compat_task()) { | ||
66 | if (addr & (sizeof(compat_long_t)-1)) | ||
67 | break; | ||
68 | ret = put_user(*(compat_long_t *)childreg, | ||
69 | (compat_long_t __user *)datap); | ||
70 | } else | ||
71 | #endif | ||
72 | { | ||
73 | if (addr & (sizeof(long)-1)) | ||
74 | break; | ||
75 | ret = put_user(*(long *)childreg, datap); | ||
76 | } | ||
91 | break; | 77 | break; |
92 | 78 | ||
93 | case PTRACE_POKEUSR: /* Write register in pt_regs. */ | 79 | case PTRACE_POKEUSR: /* Write register in pt_regs. */ |
94 | if (addr & (sizeof(data)-1)) | 80 | if (addr >= PTREGS_SIZE) |
95 | break; | 81 | break; |
96 | if (addr < 0 || addr >= PTREGS_SIZE) | 82 | childreg = (char *)task_pt_regs(child) + addr; |
97 | break; | 83 | |
98 | putreg(child, addr, data); /* Write register */ | 84 | /* Guard against overwrites of the privilege level. */ |
85 | ex1_offset = PTREGS_OFFSET_EX1; | ||
86 | #if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN) | ||
87 | if (is_compat_task()) /* point at low word */ | ||
88 | ex1_offset += sizeof(compat_long_t); | ||
89 | #endif | ||
90 | if (addr == ex1_offset) | ||
91 | data = PL_ICS_EX1(USER_PL, EX1_ICS(data)); | ||
92 | |||
93 | #ifdef CONFIG_COMPAT | ||
94 | if (is_compat_task()) { | ||
95 | if (addr & (sizeof(compat_long_t)-1)) | ||
96 | break; | ||
97 | *(compat_long_t *)childreg = data; | ||
98 | } else | ||
99 | #endif | ||
100 | { | ||
101 | if (addr & (sizeof(long)-1)) | ||
102 | break; | ||
103 | *(long *)childreg = data; | ||
104 | } | ||
99 | ret = 0; | 105 | ret = 0; |
100 | break; | 106 | break; |
101 | 107 | ||
102 | case PTRACE_GETREGS: /* Get all registers from the child. */ | 108 | case PTRACE_GETREGS: /* Get all registers from the child. */ |
103 | if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE)) | 109 | if (copy_to_user(datap, task_pt_regs(child), |
104 | break; | 110 | sizeof(struct pt_regs)) == 0) { |
105 | for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) { | 111 | ret = 0; |
106 | ret = __put_user(getreg(child, i), datap); | ||
107 | if (ret != 0) | ||
108 | break; | ||
109 | datap++; | ||
110 | } | 112 | } |
111 | break; | 113 | break; |
112 | 114 | ||
113 | case PTRACE_SETREGS: /* Set all registers in the child. */ | 115 | case PTRACE_SETREGS: /* Set all registers in the child. */ |
114 | if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE)) | 116 | if (copy_from_user(©regs, datap, |
115 | break; | 117 | sizeof(struct pt_regs)) == 0) { |
116 | for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) { | 118 | copyregs.ex1 = |
117 | ret = __get_user(tmp, datap); | 119 | PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1)); |
118 | if (ret != 0) | 120 | *task_pt_regs(child) = copyregs; |
119 | break; | 121 | ret = 0; |
120 | putreg(child, i, tmp); | ||
121 | datap++; | ||
122 | } | 122 | } |
123 | break; | 123 | break; |
124 | 124 | ||