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