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