]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/ptrace_machdep.c
libfdt: Update to 1.4.6, switch to using libfdt for overlay support
[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 "opt_compat.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/proc.h>
39 #include <sys/ptrace.h>
40 #include <sys/sysent.h>
41 #include <vm/vm.h>
42 #include <vm/pmap.h>
43 #include <machine/md_var.h>
44 #include <machine/pcb.h>
45 #include <machine/frame.h>
46 #include <machine/vmparam.h>
47
48 static int
49 cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
50 {
51         struct ptrace_xstate_info info;
52         char *savefpu;
53         int error;
54
55         if (!use_xsave)
56                 return (EOPNOTSUPP);
57
58         switch (req) {
59         case PT_GETXSTATE_OLD:
60                 fpugetregs(td);
61                 savefpu = (char *)(get_pcb_user_save_td(td) + 1);
62                 error = copyout(savefpu, addr,
63                     cpu_max_ext_state_size - sizeof(struct savefpu));
64                 break;
65
66         case PT_SETXSTATE_OLD:
67                 if (data > cpu_max_ext_state_size - sizeof(struct savefpu)) {
68                         error = EINVAL;
69                         break;
70                 }
71                 savefpu = malloc(data, M_TEMP, M_WAITOK);
72                 error = copyin(addr, savefpu, data);
73                 if (error == 0) {
74                         fpugetregs(td);
75                         error = fpusetxstate(td, savefpu, data);
76                 }
77                 free(savefpu, M_TEMP);
78                 break;
79
80         case PT_GETXSTATE_INFO:
81                 if (data != sizeof(info)) {
82                         error  = EINVAL;
83                         break;
84                 }
85                 info.xsave_len = cpu_max_ext_state_size;
86                 info.xsave_mask = xsave_mask;
87                 error = copyout(&info, addr, data);
88                 break;
89
90         case PT_GETXSTATE:
91                 fpugetregs(td);
92                 savefpu = (char *)(get_pcb_user_save_td(td));
93                 error = copyout(savefpu, addr, cpu_max_ext_state_size);
94                 break;
95
96         case PT_SETXSTATE:
97                 if (data < sizeof(struct savefpu) ||
98                     data > cpu_max_ext_state_size) {
99                         error = EINVAL;
100                         break;
101                 }
102                 savefpu = malloc(data, M_TEMP, M_WAITOK);
103                 error = copyin(addr, savefpu, data);
104                 if (error == 0)
105                         error = fpusetregs(td, (struct savefpu *)savefpu,
106                             savefpu + sizeof(struct savefpu), data -
107                             sizeof(struct savefpu));
108                 free(savefpu, M_TEMP);
109                 break;
110
111         default:
112                 error = EINVAL;
113                 break;
114         }
115
116         return (error);
117 }
118
119 static void
120 cpu_ptrace_setbase(struct thread *td, int req, register_t r)
121 {
122         struct pcb *pcb;
123
124         pcb = td->td_pcb;
125         set_pcb_flags(pcb, PCB_FULL_IRET);
126         if (req == PT_SETFSBASE) {
127                 pcb->pcb_fsbase = r;
128                 td->td_frame->tf_fs = _ufssel;
129         } else {
130                 pcb->pcb_gsbase = r;
131                 td->td_frame->tf_gs = _ugssel;
132         }
133 }
134
135 #ifdef COMPAT_FREEBSD32
136 #define PT_I386_GETXMMREGS      (PT_FIRSTMACH + 0)
137 #define PT_I386_SETXMMREGS      (PT_FIRSTMACH + 1)
138
139 static int
140 cpu32_ptrace(struct thread *td, int req, void *addr, int data)
141 {
142         struct savefpu *fpstate;
143         struct pcb *pcb;
144         uint32_t r;
145         int error;
146
147         switch (req) {
148         case PT_I386_GETXMMREGS:
149                 fpugetregs(td);
150                 error = copyout(get_pcb_user_save_td(td), addr,
151                     sizeof(*fpstate));
152                 break;
153
154         case PT_I386_SETXMMREGS:
155                 fpugetregs(td);
156                 fpstate = get_pcb_user_save_td(td);
157                 error = copyin(addr, fpstate, sizeof(*fpstate));
158                 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask;
159                 break;
160
161         case PT_GETXSTATE_OLD:
162         case PT_SETXSTATE_OLD:
163         case PT_GETXSTATE_INFO:
164         case PT_GETXSTATE:
165         case PT_SETXSTATE:
166                 error = cpu_ptrace_xstate(td, req, addr, data);
167                 break;
168
169         case PT_GETFSBASE:
170         case PT_GETGSBASE:
171                 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
172                         error = EINVAL;
173                         break;
174                 }
175                 pcb = td->td_pcb;
176                 if (td == curthread)
177                         update_pcb_bases(pcb);
178                 r = req == PT_GETFSBASE ? pcb->pcb_fsbase : pcb->pcb_gsbase;
179                 error = copyout(&r, addr, sizeof(r));
180                 break;
181
182         case PT_SETFSBASE:
183         case PT_SETGSBASE:
184                 if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
185                         error = EINVAL;
186                         break;
187                 }
188                 error = copyin(addr, &r, sizeof(r));
189                 if (error != 0)
190                         break;
191                 cpu_ptrace_setbase(td, req, r);
192                 break;
193
194         default:
195                 error = EINVAL;
196                 break;
197         }
198
199         return (error);
200 }
201 #endif
202
203 int
204 cpu_ptrace(struct thread *td, int req, void *addr, int data)
205 {
206         register_t *r, rv;
207         struct pcb *pcb;
208         int error;
209
210 #ifdef COMPAT_FREEBSD32
211         if (SV_CURPROC_FLAG(SV_ILP32))
212                 return (cpu32_ptrace(td, req, addr, data));
213 #endif
214
215         /* Support old values of PT_GETXSTATE_OLD and PT_SETXSTATE_OLD. */
216         if (req == PT_FIRSTMACH + 0)
217                 req = PT_GETXSTATE_OLD;
218         if (req == PT_FIRSTMACH + 1)
219                 req = PT_SETXSTATE_OLD;
220
221         switch (req) {
222         case PT_GETXSTATE_OLD:
223         case PT_SETXSTATE_OLD:
224         case PT_GETXSTATE_INFO:
225         case PT_GETXSTATE:
226         case PT_SETXSTATE:
227                 error = cpu_ptrace_xstate(td, req, addr, data);
228                 break;
229
230         case PT_GETFSBASE:
231         case PT_GETGSBASE:
232                 pcb = td->td_pcb;
233                 if (td == curthread)
234                         update_pcb_bases(pcb);
235                 r = req == PT_GETFSBASE ? &pcb->pcb_fsbase : &pcb->pcb_gsbase;
236                 error = copyout(r, addr, sizeof(*r));
237                 break;
238
239         case PT_SETFSBASE:
240         case PT_SETGSBASE:
241                 error = copyin(addr, &rv, sizeof(rv));
242                 if (error != 0)
243                         break;
244                 if (rv >= td->td_proc->p_sysent->sv_maxuser) {
245                         error = EINVAL;
246                         break;
247                 }
248                 cpu_ptrace_setbase(td, req, rv);
249                 break;
250
251         default:
252                 error = EINVAL;
253                 break;
254         }
255
256         return (error);
257 }