]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/i386/ptrace_machdep.c
OpenSSL: update to 3.0.11
[FreeBSD/FreeBSD.git] / sys / i386 / i386 / ptrace_machdep.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2005 Doug Rabson
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 #include "opt_cpu.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/elf.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/mutex.h>
39 #include <sys/proc.h>
40 #include <sys/ptrace.h>
41 #include <sys/reg.h>
42 #include <machine/frame.h>
43 #include <machine/md_var.h>
44 #include <machine/pcb.h>
45
46 static uint32_t
47 get_segbase(struct segment_descriptor *sdp)
48 {
49         return (sdp->sd_hibase << 24 | sdp->sd_lobase);
50 }
51
52 static bool
53 get_segbases(struct regset *rs, struct thread *td, void *buf,
54     size_t *sizep)
55 {
56         struct segbasereg *reg;
57
58         if (buf != NULL) {
59                 KASSERT(*sizep == sizeof(*reg), ("%s: invalid size", __func__));
60                 reg = buf;
61                 reg->r_fsbase = get_segbase(&td->td_pcb->pcb_fsd);
62                 reg->r_gsbase = get_segbase(&td->td_pcb->pcb_gsd);
63         }
64         *sizep = sizeof(*reg);
65         return (true);
66 }
67
68 static bool
69 set_segbases(struct regset *rs, struct thread *td, void *buf,
70     size_t size)
71 {
72         struct segbasereg *reg;
73
74         KASSERT(size == sizeof(*reg), ("%s: invalid size", __func__));
75         reg = buf;
76
77         fill_based_sd(&td->td_pcb->pcb_fsd, reg->r_fsbase);
78         td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
79         fill_based_sd(&td->td_pcb->pcb_gsd, reg->r_gsbase);
80         td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL);
81
82         return (true);
83 }
84
85 static struct regset regset_segbases = {
86         .note = NT_X86_SEGBASES,
87         .size = sizeof(struct segbasereg),
88         .get = get_segbases,
89         .set = set_segbases,
90 };
91 ELF_REGSET(regset_segbases);
92
93 static int
94 cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
95 {
96         struct ptrace_xstate_info info;
97         char *savefpu;
98         int error;
99
100         if (!use_xsave)
101                 return (EOPNOTSUPP);
102
103         switch (req) {
104         case PT_GETXSTATE_OLD:
105                 npxgetregs(td);
106                 savefpu = (char *)(get_pcb_user_save_td(td) + 1);
107                 error = copyout(savefpu, addr,
108                     cpu_max_ext_state_size - sizeof(union savefpu));
109                 break;
110
111         case PT_SETXSTATE_OLD:
112                 if (data > cpu_max_ext_state_size - sizeof(union savefpu)) {
113                         error = EINVAL;
114                         break;
115                 }
116                 savefpu = malloc(data, M_TEMP, M_WAITOK);
117                 error = copyin(addr, savefpu, data);
118                 if (error == 0) {
119                         npxgetregs(td);
120                         error = npxsetxstate(td, savefpu, data);
121                 }
122                 free(savefpu, M_TEMP);
123                 break;
124
125         case PT_GETXSTATE_INFO:
126                 if (data != sizeof(info)) {
127                         error  = EINVAL;
128                         break;
129                 }
130                 info.xsave_len = cpu_max_ext_state_size;
131                 info.xsave_mask = xsave_mask;
132                 error = copyout(&info, addr, data);
133                 break;
134
135         case PT_GETXSTATE:
136                 npxgetregs(td);
137                 savefpu = (char *)(get_pcb_user_save_td(td));
138                 error = copyout(savefpu, addr, cpu_max_ext_state_size);
139                 break;
140
141         case PT_SETXSTATE:
142                 if (data < sizeof(union savefpu) ||
143                     data > cpu_max_ext_state_size) {
144                         error = EINVAL;
145                         break;
146                 }
147                 savefpu = malloc(data, M_TEMP, M_WAITOK);
148                 error = copyin(addr, savefpu, data);
149                 if (error == 0)
150                         error = npxsetregs(td, (union savefpu *)savefpu,
151                             savefpu + sizeof(union savefpu), data -
152                             sizeof(union savefpu));
153                 free(savefpu, M_TEMP);
154                 break;
155
156         default:
157                 error = EINVAL;
158                 break;
159         }
160
161         return (error);
162 }
163
164 static int
165 cpu_ptrace_xmm(struct thread *td, int req, void *addr, int data)
166 {
167         struct savexmm *fpstate;
168         int error;
169
170         if (!cpu_fxsr)
171                 return (EINVAL);
172
173         fpstate = &get_pcb_user_save_td(td)->sv_xmm;
174         switch (req) {
175         case PT_GETXMMREGS:
176                 npxgetregs(td);
177                 error = copyout(fpstate, addr, sizeof(*fpstate));
178                 break;
179
180         case PT_SETXMMREGS:
181                 npxgetregs(td);
182                 error = copyin(addr, fpstate, sizeof(*fpstate));
183                 fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask;
184                 break;
185
186         case PT_GETXSTATE_OLD:
187         case PT_SETXSTATE_OLD:
188         case PT_GETXSTATE_INFO:
189         case PT_GETXSTATE:
190         case PT_SETXSTATE:
191                 error = cpu_ptrace_xstate(td, req, addr, data);
192                 break;
193
194         default:
195                 return (EINVAL);
196         }
197
198         return (error);
199 }
200
201 int
202 cpu_ptrace(struct thread *td, int req, void *addr, int data)
203 {
204         struct segment_descriptor *sdp, sd;
205         register_t r;
206         int error;
207
208         switch (req) {
209         case PT_GETXMMREGS:
210         case PT_SETXMMREGS:
211         case PT_GETXSTATE_OLD:
212         case PT_SETXSTATE_OLD:
213         case PT_GETXSTATE_INFO:
214         case PT_GETXSTATE:
215         case PT_SETXSTATE:
216                 error = cpu_ptrace_xmm(td, req, addr, data);
217                 break;
218
219         case PT_GETFSBASE:
220         case PT_GETGSBASE:
221                 sdp = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsd :
222                     &td->td_pcb->pcb_gsd;
223                 r = get_segbase(sdp);
224                 error = copyout(&r, addr, sizeof(r));
225                 break;
226
227         case PT_SETFSBASE:
228         case PT_SETGSBASE:
229                 error = copyin(addr, &r, sizeof(r));
230                 if (error != 0)
231                         break;
232                 fill_based_sd(&sd, r);
233                 if (req == PT_SETFSBASE) {
234                         td->td_pcb->pcb_fsd = sd;
235                         td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
236                 } else {
237                         td->td_pcb->pcb_gsd = sd;
238                         td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL);
239                 }
240                 break;
241
242         default:
243                 return (EINVAL);
244         }
245
246         return (error);
247 }
248
249 int
250 ptrace_set_pc(struct thread *td, u_long addr)
251 {
252
253         td->td_frame->tf_eip = addr;
254         return (0);
255 }
256
257 int
258 ptrace_single_step(struct thread *td)
259 {
260
261         PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
262         if ((td->td_frame->tf_eflags & PSL_T) == 0) {
263                 td->td_frame->tf_eflags |= PSL_T;
264                 td->td_dbgflags |= TDB_STEP;
265         }
266         return (0);
267 }
268
269 int
270 ptrace_clear_single_step(struct thread *td)
271 {
272
273         PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
274         td->td_frame->tf_eflags &= ~PSL_T;
275         td->td_dbgflags &= ~TDB_STEP;
276         return (0);
277 }