1 /*-
2 * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD: releng/10.3/sys/amd64/amd64/ptrace_machdep.c 286311 2015-08-05 08:17:10Z kib $");
30
31 #include "opt_compat.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/proc.h>
37 #include <sys/ptrace.h>
38 #include <sys/sysent.h>
39 #include <vm/vm.h>
40 #include <vm/pmap.h>
41 #include <machine/md_var.h>
42 #include <machine/pcb.h>
43 #include <machine/frame.h>
44 #include <machine/vmparam.h>
45
46 static int
47 cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
48 {
49 struct ptrace_xstate_info info;
50 char *savefpu;
51 int error;
52
53 if (!use_xsave)
54 return (EOPNOTSUPP);
55
56 switch (req) {
57 case PT_GETXSTATE_OLD:
58 fpugetregs(td);
59 savefpu = (char *)(get_pcb_user_save_td(td) + 1);
60 error = copyout(savefpu, addr,
61 cpu_max_ext_state_size - sizeof(struct savefpu));
62 break;
63
64 case PT_SETXSTATE_OLD:
65 if (data > cpu_max_ext_state_size - sizeof(struct savefpu)) {
66 error = EINVAL;
67 break;
68 }
69 savefpu = malloc(data, M_TEMP, M_WAITOK);
70 error = copyin(addr, savefpu, data);
71 if (error == 0) {
72 fpugetregs(td);
73 error = fpusetxstate(td, savefpu, data);
74 }
75 free(savefpu, M_TEMP);
76 break;
77
78 case PT_GETXSTATE_INFO:
79 if (data != sizeof(info)) {
80 error = EINVAL;
81 break;
82 }
83 info.xsave_len = cpu_max_ext_state_size;
84 info.xsave_mask = xsave_mask;
85 error = copyout(&info, addr, data);
86 break;
87
88 case PT_GETXSTATE:
89 fpugetregs(td);
90 savefpu = (char *)(get_pcb_user_save_td(td));
91 error = copyout(savefpu, addr, cpu_max_ext_state_size);
92 break;
93
94 case PT_SETXSTATE:
95 if (data < sizeof(struct savefpu) ||
96 data > cpu_max_ext_state_size) {
97 error = EINVAL;
98 break;
99 }
100 savefpu = malloc(data, M_TEMP, M_WAITOK);
101 error = copyin(addr, savefpu, data);
102 if (error == 0)
103 error = fpusetregs(td, (struct savefpu *)savefpu,
104 savefpu + sizeof(struct savefpu), data -
105 sizeof(struct savefpu));
106 free(savefpu, M_TEMP);
107 break;
108
109 default:
110 error = EINVAL;
111 break;
112 }
113
114 return (error);
115 }
116
117 static void
118 cpu_ptrace_setbase(struct thread *td, int req, register_t r)
119 {
120
121 if (req == PT_SETFSBASE) {
122 td->td_pcb->pcb_fsbase = r;
123 td->td_frame->tf_fs = _ufssel;
124 } else {
125 td->td_pcb->pcb_gsbase = r;
126 td->td_frame->tf_gs = _ugssel;
127 }
128 set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
129 }
130
131 #ifdef COMPAT_FREEBSD32
132 #define PT_I386_GETXMMREGS (PT_FIRSTMACH + 0)
133 #define PT_I386_SETXMMREGS (PT_FIRSTMACH + 1)
134
135 static int
136 cpu32_ptrace(struct thread *td, int req, void *addr, int data)
137 {
138 struct savefpu *fpstate;
139 uint32_t r;
140 int error;
141
142 switch (req) {
143 case PT_I386_GETXMMREGS:
144 fpugetregs(td);
145 error = copyout(get_pcb_user_save_td(td), addr,
146 sizeof(*fpstate));
147 break;
148
149 case PT_I386_SETXMMREGS:
150 fpugetregs(td);
151 fpstate = get_pcb_user_save_td(td);
152 error = copyin(addr, fpstate, sizeof(*fpstate));
153 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask;
154 break;
155
156 case PT_GETXSTATE_OLD:
157 case PT_SETXSTATE_OLD:
158 case PT_GETXSTATE_INFO:
159 case PT_GETXSTATE:
160 case PT_SETXSTATE:
161 error = cpu_ptrace_xstate(td, req, addr, data);
162 break;
163
164 case PT_GETFSBASE:
165 case PT_GETGSBASE:
166 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
167 error = EINVAL;
168 break;
169 }
170 r = req == PT_GETFSBASE ? td->td_pcb->pcb_fsbase :
171 td->td_pcb->pcb_gsbase;
172 error = copyout(&r, addr, sizeof(r));
173 break;
174
175 case PT_SETFSBASE:
176 case PT_SETGSBASE:
177 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
178 error = EINVAL;
179 break;
180 }
181 error = copyin(addr, &r, sizeof(r));
182 if (error != 0)
183 break;
184 cpu_ptrace_setbase(td, req, r);
185 break;
186
187 default:
188 error = EINVAL;
189 break;
190 }
191
192 return (error);
193 }
194 #endif
195
196 int
197 cpu_ptrace(struct thread *td, int req, void *addr, int data)
198 {
199 register_t *r, rv;
200 int error;
201
202 #ifdef COMPAT_FREEBSD32
203 if (SV_CURPROC_FLAG(SV_ILP32))
204 return (cpu32_ptrace(td, req, addr, data));
205 #endif
206
207 /* Support old values of PT_GETXSTATE_OLD and PT_SETXSTATE_OLD. */
208 if (req == PT_FIRSTMACH + 0)
209 req = PT_GETXSTATE_OLD;
210 if (req == PT_FIRSTMACH + 1)
211 req = PT_SETXSTATE_OLD;
212
213 switch (req) {
214 case PT_GETXSTATE_OLD:
215 case PT_SETXSTATE_OLD:
216 case PT_GETXSTATE_INFO:
217 case PT_GETXSTATE:
218 case PT_SETXSTATE:
219 error = cpu_ptrace_xstate(td, req, addr, data);
220 break;
221
222 case PT_GETFSBASE:
223 case PT_GETGSBASE:
224 r = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsbase :
225 &td->td_pcb->pcb_gsbase;
226 error = copyout(r, addr, sizeof(*r));
227 break;
228
229 case PT_SETFSBASE:
230 case PT_SETGSBASE:
231 error = copyin(addr, &rv, sizeof(rv));
232 if (error != 0)
233 break;
234 if (rv >= td->td_proc->p_sysent->sv_maxuser) {
235 error = EINVAL;
236 break;
237 }
238 cpu_ptrace_setbase(td, req, rv);
239 break;
240
241 default:
242 error = EINVAL;
243 break;
244 }
245
246 return (error);
247 }
Cache object: 21d50d06a82f5bbb6398ebfb0bf42bdb
|