xref: /linux/arch/x86/um/ptrace_64.c (revision ea518afc992032f7570c0a89ac9240b387dc0faf)
1 /*
2  * Copyright 2003 PathScale, Inc.
3  * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4  *
5  * Licensed under the GPL
6  */
7 
8 #include <linux/mm.h>
9 #include <linux/sched.h>
10 #include <linux/errno.h>
11 #define __FRAME_OFFSETS
12 #include <asm/ptrace.h>
13 #include <linux/uaccess.h>
14 #include <registers.h>
15 #include <asm/ptrace-abi.h>
16 
17 /*
18  * determines which flags the user has access to.
19  * 1 = access 0 = no access
20  */
21 #define FLAG_MASK 0x44dd5UL
22 
23 static const int reg_offsets[] =
24 {
25 	[R8 >> 3] = HOST_R8,
26 	[R9 >> 3] = HOST_R9,
27 	[R10 >> 3] = HOST_R10,
28 	[R11 >> 3] = HOST_R11,
29 	[R12 >> 3] = HOST_R12,
30 	[R13 >> 3] = HOST_R13,
31 	[R14 >> 3] = HOST_R14,
32 	[R15 >> 3] = HOST_R15,
33 	[RIP >> 3] = HOST_IP,
34 	[RSP >> 3] = HOST_SP,
35 	[RAX >> 3] = HOST_AX,
36 	[RBX >> 3] = HOST_BX,
37 	[RCX >> 3] = HOST_CX,
38 	[RDX >> 3] = HOST_DX,
39 	[RSI >> 3] = HOST_SI,
40 	[RDI >> 3] = HOST_DI,
41 	[RBP >> 3] = HOST_BP,
42 	[CS >> 3] = HOST_CS,
43 	[SS >> 3] = HOST_SS,
44 	[FS_BASE >> 3] = HOST_FS_BASE,
45 	[GS_BASE >> 3] = HOST_GS_BASE,
46 	[DS >> 3] = HOST_DS,
47 	[ES >> 3] = HOST_ES,
48 	[FS >> 3] = HOST_FS,
49 	[GS >> 3] = HOST_GS,
50 	[EFLAGS >> 3] = HOST_EFLAGS,
51 	[ORIG_RAX >> 3] = HOST_ORIG_AX,
52 };
53 
54 int putreg(struct task_struct *child, int regno, unsigned long value)
55 {
56 	switch (regno) {
57 	case R8:
58 	case R9:
59 	case R10:
60 	case R11:
61 	case R12:
62 	case R13:
63 	case R14:
64 	case R15:
65 	case RIP:
66 	case RSP:
67 	case RAX:
68 	case RBX:
69 	case RCX:
70 	case RDX:
71 	case RSI:
72 	case RDI:
73 	case RBP:
74 		break;
75 
76 	case ORIG_RAX:
77 		/* Update the syscall number. */
78 		UPT_SYSCALL_NR(&child->thread.regs.regs) = value;
79 		break;
80 
81 	case FS:
82 	case GS:
83 	case DS:
84 	case ES:
85 	case SS:
86 	case CS:
87 		if (value && (value & 3) != 3)
88 			return -EIO;
89 		value &= 0xffff;
90 		break;
91 
92 	case FS_BASE:
93 	case GS_BASE:
94 		if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
95 			return -EIO;
96 		break;
97 
98 	case EFLAGS:
99 		value &= FLAG_MASK;
100 		child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
101 		return 0;
102 
103 	default:
104 		panic("Bad register in putreg(): %d\n", regno);
105 	}
106 
107 	child->thread.regs.regs.gp[reg_offsets[regno >> 3]] = value;
108 	return 0;
109 }
110 
111 int poke_user(struct task_struct *child, long addr, long data)
112 {
113 	if ((addr & 3) || addr < 0)
114 		return -EIO;
115 
116 	if (addr < MAX_REG_OFFSET)
117 		return putreg(child, addr, data);
118 	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
119 		(addr <= offsetof(struct user, u_debugreg[7]))) {
120 		addr -= offsetof(struct user, u_debugreg[0]);
121 		addr = addr >> 3;
122 		if ((addr == 4) || (addr == 5))
123 			return -EIO;
124 		child->thread.arch.debugregs[addr] = data;
125 		return 0;
126 	}
127 	return -EIO;
128 }
129 
130 unsigned long getreg(struct task_struct *child, int regno)
131 {
132 	unsigned long mask = ~0UL;
133 
134 	switch (regno) {
135 	case R8:
136 	case R9:
137 	case R10:
138 	case R11:
139 	case R12:
140 	case R13:
141 	case R14:
142 	case R15:
143 	case RIP:
144 	case RSP:
145 	case RAX:
146 	case RBX:
147 	case RCX:
148 	case RDX:
149 	case RSI:
150 	case RDI:
151 	case RBP:
152 	case ORIG_RAX:
153 	case EFLAGS:
154 	case FS_BASE:
155 	case GS_BASE:
156 		break;
157 	case FS:
158 	case GS:
159 	case DS:
160 	case ES:
161 	case SS:
162 	case CS:
163 		mask = 0xffff;
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 >> 3]];
169 }
170 
171 int peek_user(struct task_struct *child, long addr, long data)
172 {
173 	/* read the word at location addr in the USER area. */
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 	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
183 		(addr <= offsetof(struct user, u_debugreg[7]))) {
184 		addr -= offsetof(struct user, u_debugreg[0]);
185 		addr = addr >> 2;
186 		tmp = child->thread.arch.debugregs[addr];
187 	}
188 	return put_user(tmp, (unsigned long *) data);
189 }
190 
191 static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
192 {
193 	int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
194 	struct user_i387_struct fpregs;
195 
196 	err = save_i387_registers(userspace_pid[cpu],
197 				  (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_i387_registers(userspace_pid[cpu],
218 				      (unsigned long *) &fpregs);
219 }
220 
221 long subarch_ptrace(struct task_struct *child, long request,
222 		    unsigned long addr, unsigned long data)
223 {
224 	int ret = -EIO;
225 	void __user *datap = (void __user *) data;
226 
227 	switch (request) {
228 	case PTRACE_GETFPREGS: /* Get the child FPU state. */
229 		ret = get_fpregs(datap, child);
230 		break;
231 	case PTRACE_SETFPREGS: /* Set the child FPU state. */
232 		ret = set_fpregs(datap, child);
233 		break;
234 	case PTRACE_ARCH_PRCTL:
235 		/* XXX Calls ptrace on the host - needs some SMP thinking */
236 		ret = arch_prctl(child, data, (void __user *) addr);
237 		break;
238 	}
239 
240 	return ret;
241 }
242