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

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

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

~ [ 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