xref: /linux/arch/x86/um/ptrace_64.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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 #include <linux/regset.h>
12 #define __FRAME_OFFSETS
13 #include <asm/ptrace.h>
14 #include <linux/uaccess.h>
15 #include <registers.h>
16 #include <asm/ptrace-abi.h>
17 
18 /*
19  * determines which flags the user has access to.
20  * 1 = access 0 = no access
21  */
22 #define FLAG_MASK 0x44dd5UL
23 
24 static const int reg_offsets[] =
25 {
26 	[R8 >> 3] = HOST_R8,
27 	[R9 >> 3] = HOST_R9,
28 	[R10 >> 3] = HOST_R10,
29 	[R11 >> 3] = HOST_R11,
30 	[R12 >> 3] = HOST_R12,
31 	[R13 >> 3] = HOST_R13,
32 	[R14 >> 3] = HOST_R14,
33 	[R15 >> 3] = HOST_R15,
34 	[RIP >> 3] = HOST_IP,
35 	[RSP >> 3] = HOST_SP,
36 	[RAX >> 3] = HOST_AX,
37 	[RBX >> 3] = HOST_BX,
38 	[RCX >> 3] = HOST_CX,
39 	[RDX >> 3] = HOST_DX,
40 	[RSI >> 3] = HOST_SI,
41 	[RDI >> 3] = HOST_DI,
42 	[RBP >> 3] = HOST_BP,
43 	[CS >> 3] = HOST_CS,
44 	[SS >> 3] = HOST_SS,
45 	[FS_BASE >> 3] = HOST_FS_BASE,
46 	[GS_BASE >> 3] = HOST_GS_BASE,
47 	[DS >> 3] = HOST_DS,
48 	[ES >> 3] = HOST_ES,
49 	[FS >> 3] = HOST_FS,
50 	[GS >> 3] = HOST_GS,
51 	[EFLAGS >> 3] = HOST_EFLAGS,
52 	[ORIG_RAX >> 3] = HOST_ORIG_AX,
53 };
54 
55 int putreg(struct task_struct *child, int regno, unsigned long value)
56 {
57 	switch (regno) {
58 	case R8:
59 	case R9:
60 	case R10:
61 	case R11:
62 	case R12:
63 	case R13:
64 	case R14:
65 	case R15:
66 	case RIP:
67 	case RSP:
68 	case RAX:
69 	case RBX:
70 	case RCX:
71 	case RDX:
72 	case RSI:
73 	case RDI:
74 	case RBP:
75 		break;
76 
77 	case ORIG_RAX:
78 		/* Update the syscall number. */
79 		UPT_SYSCALL_NR(&child->thread.regs.regs) = value;
80 		break;
81 
82 	case FS:
83 	case GS:
84 	case DS:
85 	case ES:
86 	case SS:
87 	case CS:
88 		if (value && (value & 3) != 3)
89 			return -EIO;
90 		value &= 0xffff;
91 		break;
92 
93 	case FS_BASE:
94 	case GS_BASE:
95 		if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
96 			return -EIO;
97 		break;
98 
99 	case EFLAGS:
100 		value &= FLAG_MASK;
101 		child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
102 		return 0;
103 
104 	default:
105 		panic("Bad register in putreg(): %d\n", regno);
106 	}
107 
108 	child->thread.regs.regs.gp[reg_offsets[regno >> 3]] = value;
109 	return 0;
110 }
111 
112 int poke_user(struct task_struct *child, long addr, long data)
113 {
114 	if ((addr & 3) || addr < 0)
115 		return -EIO;
116 
117 	if (addr < MAX_REG_OFFSET)
118 		return putreg(child, addr, data);
119 	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
120 		(addr <= offsetof(struct user, u_debugreg[7]))) {
121 		addr -= offsetof(struct user, u_debugreg[0]);
122 		addr = addr >> 3;
123 		if ((addr == 4) || (addr == 5))
124 			return -EIO;
125 		child->thread.arch.debugregs[addr] = data;
126 		return 0;
127 	}
128 	return -EIO;
129 }
130 
131 unsigned long getreg(struct task_struct *child, int regno)
132 {
133 	unsigned long mask = ~0UL;
134 
135 	switch (regno) {
136 	case R8:
137 	case R9:
138 	case R10:
139 	case R11:
140 	case R12:
141 	case R13:
142 	case R14:
143 	case R15:
144 	case RIP:
145 	case RSP:
146 	case RAX:
147 	case RBX:
148 	case RCX:
149 	case RDX:
150 	case RSI:
151 	case RDI:
152 	case RBP:
153 	case ORIG_RAX:
154 	case EFLAGS:
155 	case FS_BASE:
156 	case GS_BASE:
157 		break;
158 	case FS:
159 	case GS:
160 	case DS:
161 	case ES:
162 	case SS:
163 	case CS:
164 		mask = 0xffff;
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 >> 3]];
170 }
171 
172 int peek_user(struct task_struct *child, long addr, long data)
173 {
174 	/* read the word at location addr in the USER area. */
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 	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 *) data);
190 }
191 
192 long subarch_ptrace(struct task_struct *child, long request,
193 		    unsigned long addr, unsigned long data)
194 {
195 	int ret = -EIO;
196 	void __user *datap = (void __user *) data;
197 
198 	switch (request) {
199 	case PTRACE_GETFPREGS: /* Get the child FPU state. */
200 		return copy_regset_to_user(child, task_user_regset_view(child),
201 					   REGSET_FP,
202 					   0, sizeof(struct user_i387_struct),
203 					   datap);
204 	case PTRACE_SETFPREGS: /* Set the child FPU state. */
205 		return copy_regset_from_user(child, task_user_regset_view(child),
206 					     REGSET_FP,
207 					     0, sizeof(struct user_i387_struct),
208 					     datap);
209 	case PTRACE_ARCH_PRCTL:
210 		/* XXX Calls ptrace on the host - needs some SMP thinking */
211 		ret = arch_prctl(child, data, (void __user *) addr);
212 		break;
213 	}
214 
215 	return ret;
216 }
217