]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/ptrace_machdep.c
Merge OpenSSL 1.0.2m.
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / ptrace_machdep.c
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$");
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         struct pcb *pcb;
121
122         pcb = td->td_pcb;
123         set_pcb_flags(pcb, PCB_FULL_IRET);
124         if (req == PT_SETFSBASE) {
125                 pcb->pcb_fsbase = r;
126                 td->td_frame->tf_fs = _ufssel;
127         } else {
128                 pcb->pcb_gsbase = r;
129                 td->td_frame->tf_gs = _ugssel;
130         }
131 }
132
133 #ifdef COMPAT_FREEBSD32
134 #define PT_I386_GETXMMREGS      (PT_FIRSTMACH + 0)
135 #define PT_I386_SETXMMREGS      (PT_FIRSTMACH + 1)
136
137 static int
138 cpu32_ptrace(struct thread *td, int req, void *addr, int data)
139 {
140         struct savefpu *fpstate;
141         struct pcb *pcb;
142         uint32_t r;
143         int error;
144
145         switch (req) {
146         case PT_I386_GETXMMREGS:
147                 fpugetregs(td);
148                 error = copyout(get_pcb_user_save_td(td), addr,
149                     sizeof(*fpstate));
150                 break;
151
152         case PT_I386_SETXMMREGS:
153                 fpugetregs(td);
154                 fpstate = get_pcb_user_save_td(td);
155                 error = copyin(addr, fpstate, sizeof(*fpstate));
156                 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask;
157                 break;
158
159         case PT_GETXSTATE_OLD:
160         case PT_SETXSTATE_OLD:
161         case PT_GETXSTATE_INFO:
162         case PT_GETXSTATE:
163         case PT_SETXSTATE:
164                 error = cpu_ptrace_xstate(td, req, addr, data);
165                 break;
166
167         case PT_GETFSBASE:
168         case PT_GETGSBASE:
169                 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
170                         error = EINVAL;
171                         break;
172                 }
173                 pcb = td->td_pcb;
174                 if (td == curthread)
175                         update_pcb_bases(pcb);
176                 r = req == PT_GETFSBASE ? pcb->pcb_fsbase : pcb->pcb_gsbase;
177                 error = copyout(&r, addr, sizeof(r));
178                 break;
179
180         case PT_SETFSBASE:
181         case PT_SETGSBASE:
182                 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
183                         error = EINVAL;
184                         break;
185                 }
186                 error = copyin(addr, &r, sizeof(r));
187                 if (error != 0)
188                         break;
189                 cpu_ptrace_setbase(td, req, r);
190                 break;
191
192         default:
193                 error = EINVAL;
194                 break;
195         }
196
197         return (error);
198 }
199 #endif
200
201 int
202 cpu_ptrace(struct thread *td, int req, void *addr, int data)
203 {
204         register_t *r, rv;
205         struct pcb *pcb;
206         int error;
207
208 #ifdef COMPAT_FREEBSD32
209         if (SV_CURPROC_FLAG(SV_ILP32))
210                 return (cpu32_ptrace(td, req, addr, data));
211 #endif
212
213         /* Support old values of PT_GETXSTATE_OLD and PT_SETXSTATE_OLD. */
214         if (req == PT_FIRSTMACH + 0)
215                 req = PT_GETXSTATE_OLD;
216         if (req == PT_FIRSTMACH + 1)
217                 req = PT_SETXSTATE_OLD;
218
219         switch (req) {
220         case PT_GETXSTATE_OLD:
221         case PT_SETXSTATE_OLD:
222         case PT_GETXSTATE_INFO:
223         case PT_GETXSTATE:
224         case PT_SETXSTATE:
225                 error = cpu_ptrace_xstate(td, req, addr, data);
226                 break;
227
228         case PT_GETFSBASE:
229         case PT_GETGSBASE:
230                 pcb = td->td_pcb;
231                 if (td == curthread)
232                         update_pcb_bases(pcb);
233                 r = req == PT_GETFSBASE ? &pcb->pcb_fsbase : &pcb->pcb_gsbase;
234                 error = copyout(r, addr, sizeof(*r));
235                 break;
236
237         case PT_SETFSBASE:
238         case PT_SETGSBASE:
239                 error = copyin(addr, &rv, sizeof(rv));
240                 if (error != 0)
241                         break;
242                 if (rv >= td->td_proc->p_sysent->sv_maxuser) {
243                         error = EINVAL;
244                         break;
245                 }
246                 cpu_ptrace_setbase(td, req, rv);
247                 break;
248
249         default:
250                 error = EINVAL;
251                 break;
252         }
253
254         return (error);
255 }