19
19
#include <linux/kprobes.h>
20
20
#include <linux/compat.h>
21
21
#include <linux/uaccess.h>
22
+ #include <linux/regset.h>
23
+ #include <linux/elf.h>
22
24
#include <asm/traps.h>
25
+ #include <arch/chip.h>
23
26
24
27
void user_enable_single_step (struct task_struct * child )
25
28
{
@@ -45,6 +48,100 @@ void ptrace_disable(struct task_struct *child)
45
48
clear_tsk_thread_flag (child , TIF_SYSCALL_TRACE );
46
49
}
47
50
51
+ /*
52
+ * Get registers from task and ready the result for userspace.
53
+ * Note that we localize the API issues to getregs() and putregs() at
54
+ * some cost in performance, e.g. we need a full pt_regs copy for
55
+ * PEEKUSR, and two copies for POKEUSR. But in general we expect
56
+ * GETREGS/PUTREGS to be the API of choice anyway.
57
+ */
58
+ static char * getregs (struct task_struct * child , struct pt_regs * uregs )
59
+ {
60
+ * uregs = * task_pt_regs (child );
61
+
62
+ /* Set up flags ABI bits. */
63
+ uregs -> flags = 0 ;
64
+ #ifdef CONFIG_COMPAT
65
+ if (task_thread_info (child )-> status & TS_COMPAT )
66
+ uregs -> flags |= PT_FLAGS_COMPAT ;
67
+ #endif
68
+
69
+ return (char * )uregs ;
70
+ }
71
+
72
+ /* Put registers back to task. */
73
+ static void putregs (struct task_struct * child , struct pt_regs * uregs )
74
+ {
75
+ struct pt_regs * regs = task_pt_regs (child );
76
+
77
+ /* Don't allow overwriting the kernel-internal flags word. */
78
+ uregs -> flags = regs -> flags ;
79
+
80
+ /* Only allow setting the ICS bit in the ex1 word. */
81
+ uregs -> ex1 = PL_ICS_EX1 (USER_PL , EX1_ICS (uregs -> ex1 ));
82
+
83
+ * regs = * uregs ;
84
+ }
85
+
86
+ enum tile_regset {
87
+ REGSET_GPR ,
88
+ };
89
+
90
+ static int tile_gpr_get (struct task_struct * target ,
91
+ const struct user_regset * regset ,
92
+ unsigned int pos , unsigned int count ,
93
+ void * kbuf , void __user * ubuf )
94
+ {
95
+ struct pt_regs regs ;
96
+
97
+ getregs (target , & regs );
98
+
99
+ return user_regset_copyout (& pos , & count , & kbuf , & ubuf , & regs , 0 ,
100
+ sizeof (regs ));
101
+ }
102
+
103
+ static int tile_gpr_set (struct task_struct * target ,
104
+ const struct user_regset * regset ,
105
+ unsigned int pos , unsigned int count ,
106
+ const void * kbuf , const void __user * ubuf )
107
+ {
108
+ int ret ;
109
+ struct pt_regs regs ;
110
+
111
+ ret = user_regset_copyin (& pos , & count , & kbuf , & ubuf , & regs , 0 ,
112
+ sizeof (regs ));
113
+ if (ret )
114
+ return ret ;
115
+
116
+ putregs (target , & regs );
117
+
118
+ return 0 ;
119
+ }
120
+
121
+ static const struct user_regset tile_user_regset [] = {
122
+ [REGSET_GPR ] = {
123
+ .core_note_type = NT_PRSTATUS ,
124
+ .n = ELF_NGREG ,
125
+ .size = sizeof (elf_greg_t ),
126
+ .align = sizeof (elf_greg_t ),
127
+ .get = tile_gpr_get ,
128
+ .set = tile_gpr_set ,
129
+ },
130
+ };
131
+
132
+ static const struct user_regset_view tile_user_regset_view = {
133
+ .name = CHIP_ARCH_NAME ,
134
+ .e_machine = ELF_ARCH ,
135
+ .ei_osabi = ELF_OSABI ,
136
+ .regsets = tile_user_regset ,
137
+ .n = ARRAY_SIZE (tile_user_regset ),
138
+ };
139
+
140
+ const struct user_regset_view * task_user_regset_view (struct task_struct * task )
141
+ {
142
+ return & tile_user_regset_view ;
143
+ }
144
+
48
145
long arch_ptrace (struct task_struct * child , long request ,
49
146
unsigned long addr , unsigned long data )
50
147
{
@@ -53,14 +150,13 @@ long arch_ptrace(struct task_struct *child, long request,
53
150
long ret = - EIO ;
54
151
char * childreg ;
55
152
struct pt_regs copyregs ;
56
- int ex1_offset ;
57
153
58
154
switch (request ) {
59
155
60
156
case PTRACE_PEEKUSR : /* Read register from pt_regs. */
61
157
if (addr >= PTREGS_SIZE )
62
158
break ;
63
- childreg = ( char * ) task_pt_regs ( child ) + addr ;
159
+ childreg = getregs ( child , & copyregs ) + addr ;
64
160
#ifdef CONFIG_COMPAT
65
161
if (is_compat_task ()) {
66
162
if (addr & (sizeof (compat_long_t )- 1 ))
@@ -79,17 +175,7 @@ long arch_ptrace(struct task_struct *child, long request,
79
175
case PTRACE_POKEUSR : /* Write register in pt_regs. */
80
176
if (addr >= PTREGS_SIZE )
81
177
break ;
82
- childreg = (char * )task_pt_regs (child ) + addr ;
83
-
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
-
178
+ childreg = getregs (child , & copyregs ) + addr ;
93
179
#ifdef CONFIG_COMPAT
94
180
if (is_compat_task ()) {
95
181
if (addr & (sizeof (compat_long_t )- 1 ))
@@ -102,24 +188,20 @@ long arch_ptrace(struct task_struct *child, long request,
102
188
break ;
103
189
* (long * )childreg = data ;
104
190
}
191
+ putregs (child , & copyregs );
105
192
ret = 0 ;
106
193
break ;
107
194
108
195
case PTRACE_GETREGS : /* Get all registers from the child. */
109
- if (copy_to_user (datap , task_pt_regs (child ),
110
- sizeof (struct pt_regs )) == 0 ) {
111
- ret = 0 ;
112
- }
196
+ ret = copy_regset_to_user (child , & tile_user_regset_view ,
197
+ REGSET_GPR , 0 ,
198
+ sizeof (struct pt_regs ), datap );
113
199
break ;
114
200
115
201
case PTRACE_SETREGS : /* Set all registers in the child. */
116
- if (copy_from_user (& copyregs , datap ,
117
- sizeof (struct pt_regs )) == 0 ) {
118
- copyregs .ex1 =
119
- PL_ICS_EX1 (USER_PL , EX1_ICS (copyregs .ex1 ));
120
- * task_pt_regs (child ) = copyregs ;
121
- ret = 0 ;
122
- }
202
+ ret = copy_regset_from_user (child , & tile_user_regset_view ,
203
+ REGSET_GPR , 0 ,
204
+ sizeof (struct pt_regs ), datap );
123
205
break ;
124
206
125
207
case PTRACE_GETFPREGS : /* Get the child FPU state. */
@@ -128,12 +210,16 @@ long arch_ptrace(struct task_struct *child, long request,
128
210
129
211
case PTRACE_SETOPTIONS :
130
212
/* Support TILE-specific ptrace options. */
131
- child -> ptrace &= ~ PT_TRACE_MASK_TILE ;
213
+ BUILD_BUG_ON ( PTRACE_O_MASK_TILE & PTRACE_O_MASK ) ;
132
214
tmp = data & PTRACE_O_MASK_TILE ;
133
215
data &= ~PTRACE_O_MASK_TILE ;
134
216
ret = ptrace_request (child , request , addr , data );
135
- if (tmp & PTRACE_O_TRACEMIGRATE )
136
- child -> ptrace |= PT_TRACE_MIGRATE ;
217
+ if (ret == 0 ) {
218
+ unsigned int flags = child -> ptrace ;
219
+ flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT );
220
+ flags |= (tmp << PT_OPT_FLAG_SHIFT );
221
+ child -> ptrace = flags ;
222
+ }
137
223
break ;
138
224
139
225
default :
0 commit comments