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