~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/um/ptrace_32.c

Version: ~ [ linux-5.12 ] ~ [ linux-5.11.16 ] ~ [ linux-5.10.32 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.114 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.188 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.231 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.267 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.267 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  3  * Licensed under the GPL
  4  */
  5 
  6 #include <linux/mm.h>
  7 #include <linux/sched.h>
  8 #include <asm/uaccess.h>
  9 #include <skas.h>
 10 
 11 extern int arch_switch_tls(struct task_struct *to);
 12 
 13 void arch_switch_to(struct task_struct *to)
 14 {
 15         int err = arch_switch_tls(to);
 16         if (!err)
 17                 return;
 18 
 19         if (err != -EINVAL)
 20                 printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
 21                        "not EINVAL\n", -err);
 22         else
 23                 printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
 24 }
 25 
 26 int is_syscall(unsigned long addr)
 27 {
 28         unsigned short instr;
 29         int n;
 30 
 31         n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
 32         if (n) {
 33                 /* access_process_vm() grants access to vsyscall and stub,
 34                  * while copy_from_user doesn't. Maybe access_process_vm is
 35                  * slow, but that doesn't matter, since it will be called only
 36                  * in case of singlestepping, if copy_from_user failed.
 37                  */
 38                 n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
 39                 if (n != sizeof(instr)) {
 40                         printk(KERN_ERR "is_syscall : failed to read "
 41                                "instruction from 0x%lx\n", addr);
 42                         return 1;
 43                 }
 44         }
 45         /* int 0x80 or sysenter */
 46         return (instr == 0x80cd) || (instr == 0x340f);
 47 }
 48 
 49 /* determines which flags the user has access to. */
 50 /* 1 = access 0 = no access */
 51 #define FLAG_MASK 0x00044dd5
 52 
 53 static const int reg_offsets[] = {
 54         [EBX] = HOST_BX,
 55         [ECX] = HOST_CX,
 56         [EDX] = HOST_DX,
 57         [ESI] = HOST_SI,
 58         [EDI] = HOST_DI,
 59         [EBP] = HOST_BP,
 60         [EAX] = HOST_AX,
 61         [DS] = HOST_DS,
 62         [ES] = HOST_ES,
 63         [FS] = HOST_FS,
 64         [GS] = HOST_GS,
 65         [EIP] = HOST_IP,
 66         [CS] = HOST_CS,
 67         [EFL] = HOST_EFLAGS,
 68         [UESP] = HOST_SP,
 69         [SS] = HOST_SS,
 70 };
 71 
 72 int putreg(struct task_struct *child, int regno, unsigned long value)
 73 {
 74         regno >>= 2;
 75         switch (regno) {
 76         case EBX:
 77         case ECX:
 78         case EDX:
 79         case ESI:
 80         case EDI:
 81         case EBP:
 82         case EAX:
 83         case EIP:
 84         case UESP:
 85                 break;
 86         case FS:
 87                 if (value && (value & 3) != 3)
 88                         return -EIO;
 89                 break;
 90         case GS:
 91                 if (value && (value & 3) != 3)
 92                         return -EIO;
 93                 break;
 94         case DS:
 95         case ES:
 96                 if (value && (value & 3) != 3)
 97                         return -EIO;
 98                 value &= 0xffff;
 99                 break;
100         case SS:
101         case CS:
102                 if ((value & 3) != 3)
103                         return -EIO;
104                 value &= 0xffff;
105                 break;
106         case EFL:
107                 value &= FLAG_MASK;
108                 child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
109                 return 0;
110         case ORIG_EAX:
111                 child->thread.regs.regs.syscall = value;
112                 return 0;
113         default :
114                 panic("Bad register in putreg() : %d\n", regno);
115         }
116         child->thread.regs.regs.gp[reg_offsets[regno]] = value;
117         return 0;
118 }
119 
120 int poke_user(struct task_struct *child, long addr, long data)
121 {
122         if ((addr & 3) || addr < 0)
123                 return -EIO;
124 
125         if (addr < MAX_REG_OFFSET)
126                 return putreg(child, addr, data);
127         else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
128                  (addr <= offsetof(struct user, u_debugreg[7]))) {
129                 addr -= offsetof(struct user, u_debugreg[0]);
130                 addr = addr >> 2;
131                 if ((addr == 4) || (addr == 5))
132                         return -EIO;
133                 child->thread.arch.debugregs[addr] = data;
134                 return 0;
135         }
136         return -EIO;
137 }
138 
139 unsigned long getreg(struct task_struct *child, int regno)
140 {
141         unsigned long mask = ~0UL;
142 
143         regno >>= 2;
144         switch (regno) {
145         case ORIG_EAX:
146                 return child->thread.regs.regs.syscall;
147         case FS:
148         case GS:
149         case DS:
150         case ES:
151         case SS:
152         case CS:
153                 mask = 0xffff;
154                 break;
155         case EIP:
156         case UESP:
157         case EAX:
158         case EBX:
159         case ECX:
160         case EDX:
161         case ESI:
162         case EDI:
163         case EBP:
164         case EFL:
165                 break;
166         default:
167                 panic("Bad register in getreg() : %d\n", regno);
168         }
169         return mask & child->thread.regs.regs.gp[reg_offsets[regno]];
170 }
171 
172 /* read the word at location addr in the USER area. */
173 int peek_user(struct task_struct *child, long addr, long data)
174 {
175         unsigned long tmp;
176 
177         if ((addr & 3) || addr < 0)
178                 return -EIO;
179 
180         tmp = 0;  /* Default return condition */
181         if (addr < MAX_REG_OFFSET) {
182                 tmp = getreg(child, addr);
183         }
184         else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
185                  (addr <= offsetof(struct user, u_debugreg[7]))) {
186                 addr -= offsetof(struct user, u_debugreg[0]);
187                 addr = addr >> 2;
188                 tmp = child->thread.arch.debugregs[addr];
189         }
190         return put_user(tmp, (unsigned long __user *) data);
191 }
192 
193 static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
194 {
195         int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
196         struct user_i387_struct fpregs;
197 
198         err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
199         if (err)
200                 return err;
201 
202         n = copy_to_user(buf, &fpregs, sizeof(fpregs));
203         if(n > 0)
204                 return -EFAULT;
205 
206         return n;
207 }
208 
209 static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
210 {
211         int n, cpu = ((struct thread_info *) child->stack)->cpu;
212         struct user_i387_struct fpregs;
213 
214         n = copy_from_user(&fpregs, buf, sizeof(fpregs));
215         if (n > 0)
216                 return -EFAULT;
217 
218         return restore_fp_registers(userspace_pid[cpu],
219                                     (unsigned long *) &fpregs);
220 }
221 
222 static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
223 {
224         int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
225         struct user_fxsr_struct fpregs;
226 
227         err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
228         if (err)
229                 return err;
230 
231         n = copy_to_user(buf, &fpregs, sizeof(fpregs));
232         if(n > 0)
233                 return -EFAULT;
234 
235         return n;
236 }
237 
238 static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
239 {
240         int n, cpu = ((struct thread_info *) child->stack)->cpu;
241         struct user_fxsr_struct fpregs;
242 
243         n = copy_from_user(&fpregs, buf, sizeof(fpregs));
244         if (n > 0)
245                 return -EFAULT;
246 
247         return restore_fpx_registers(userspace_pid[cpu],
248                                      (unsigned long *) &fpregs);
249 }
250 
251 long subarch_ptrace(struct task_struct *child, long request,
252                     unsigned long addr, unsigned long data)
253 {
254         int ret = -EIO;
255         void __user *datap = (void __user *) data;
256         switch (request) {
257         case PTRACE_GETFPREGS: /* Get the child FPU state. */
258                 ret = get_fpregs(datap, child);
259                 break;
260         case PTRACE_SETFPREGS: /* Set the child FPU state. */
261                 ret = set_fpregs(datap, child);
262                 break;
263         case PTRACE_GETFPXREGS: /* Get the child FPU state. */
264                 ret = get_fpxregs(datap, child);
265                 break;
266         case PTRACE_SETFPXREGS: /* Set the child FPU state. */
267                 ret = set_fpxregs(datap, child);
268                 break;
269         default:
270                 ret = -EIO;
271         }
272         return ret;
273 }
274 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp