sys_process_lwpstatus.c revision 1.3 1 /* $NetBSD: sys_process_lwpstatus.c,v 1.3 2020/10/20 22:31:20 rin Exp $ */
2
3 /*-
4 * Copyright (c) 2019 The NetBSD Foundation, Inc.
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.3 2020/10/20 22:31:20 rin Exp $");
31
32 #ifdef _KERNEL_OPT
33 #include "opt_ptrace.h"
34 #include "opt_ktrace.h"
35 #include "opt_pax.h"
36 #include "opt_compat_netbsd32.h"
37 #endif
38
39 #if defined(__HAVE_COMPAT_NETBSD32) && !defined(COMPAT_NETBSD32) \
40 && !defined(_RUMPKERNEL)
41 #define COMPAT_NETBSD32
42 #endif
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/lwp.h>
48 #include <sys/proc.h>
49 #include <sys/ptrace.h>
50
51 #ifndef PTRACE_REGS_ALIGN
52 #define PTRACE_REGS_ALIGN /* nothing */
53 #endif
54
55 void
56 ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
57 {
58
59 KASSERT(l->l_lid == pls->pl_lwpid);
60
61 memcpy(&pls->pl_sigmask, &l->l_sigmask, sizeof(pls->pl_sigmask));
62 memcpy(&pls->pl_sigpend, &l->l_sigpend.sp_set, sizeof(pls->pl_sigpend));
63
64 if (l->l_name == NULL)
65 memset(&pls->pl_name, 0, PL_LNAMELEN);
66 else {
67 KASSERT(strlen(l->l_name) < PL_LNAMELEN);
68 strncpy(pls->pl_name, l->l_name, PL_LNAMELEN);
69 }
70
71 #ifdef PTRACE_LWP_GETPRIVATE
72 pls->pl_private = (void *)(intptr_t)PTRACE_LWP_GETPRIVATE(l);
73 #else
74 pls->pl_private = l->l_private;
75 #endif
76 }
77
78 void
79 process_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
80 {
81
82 pls->pl_lwpid = l->l_lid;
83
84 ptrace_read_lwpstatus(l, pls);
85 }
86
87 int
88 ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid)
89 {
90 if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
91 return 0;
92
93 mutex_enter(t->p_lock);
94 lwp_delref2(*lt);
95
96 *lt = lwp_find(t, lid);
97 if (*lt == NULL) {
98 mutex_exit(t->p_lock);
99 return ESRCH;
100 }
101
102 if ((*lt)->l_flag & LW_SYSTEM) {
103 mutex_exit(t->p_lock);
104 *lt = NULL;
105 return EINVAL;
106 }
107
108 lwp_addref(*lt);
109 mutex_exit(t->p_lock);
110
111 return 0;
112 }
113
114 int
115 process_validfpregs(struct lwp *l)
116 {
117
118 #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
119 return (l->l_flag & LW_SYSTEM) == 0;
120 #else
121 return 0;
122 #endif
123 }
124
125 int
126 process_validregs(struct lwp *l)
127 {
128
129 #if defined(PT_SETREGS) || defined(PT_GETREGS)
130 return (l->l_flag & LW_SYSTEM) == 0;
131 #else
132 return 0;
133 #endif
134 }
135
136 int
137 process_validdbregs(struct lwp *l)
138 {
139
140 #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
141 return (l->l_flag & LW_SYSTEM) == 0;
142 #else
143 return 0;
144 #endif
145 }
146
147 #ifdef PT_REGISTERS
148 static int
149 proc_regio(struct lwp *l, struct uio *uio, size_t ks, ptrace_regrfunc_t r,
150 ptrace_regwfunc_t w)
151 {
152 char buf[1024] PTRACE_REGS_ALIGN;
153 int error;
154 char *kv;
155 size_t kl;
156
157 if (ks > sizeof(buf))
158 return E2BIG;
159
160 if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks)
161 return EINVAL;
162
163 kv = buf + uio->uio_offset;
164 kl = ks - uio->uio_offset;
165
166 if (kl > uio->uio_resid)
167 kl = uio->uio_resid;
168
169 error = (*r)(l, buf, &ks);
170 if (error == 0)
171 error = uiomove(kv, kl, uio);
172 if (error == 0 && uio->uio_rw == UIO_WRITE) {
173 if (l->l_stat != LSSTOP)
174 error = EBUSY;
175 else
176 error = (*w)(l, buf, ks);
177 }
178
179 uio->uio_offset = 0;
180 return error;
181 }
182 #endif
183
184 int
185 process_doregs(struct lwp *curl /*tracer*/,
186 struct lwp *l /*traced*/,
187 struct uio *uio)
188 {
189 #if defined(PT_GETREGS) || defined(PT_SETREGS)
190 size_t s;
191 ptrace_regrfunc_t r;
192 ptrace_regwfunc_t w;
193
194 #ifdef COMPAT_NETBSD32
195 const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
196
197 if (__predict_false(pk32)) {
198 if ((l->l_proc->p_flag & PK_32) == 0) {
199 // 32 bit tracer can't trace 64 bit process
200 return EINVAL;
201 }
202 s = sizeof(process_reg32);
203 r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs32);
204 w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs32);
205 } else
206 #endif
207 {
208 s = sizeof(struct reg);
209 r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs);
210 w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs);
211 }
212 return proc_regio(l, uio, s, r, w);
213 #else
214 return EINVAL;
215 #endif
216 }
217
218 int
219 process_dofpregs(struct lwp *curl /*tracer*/,
220 struct lwp *l /*traced*/,
221 struct uio *uio)
222 {
223 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
224 size_t s;
225 ptrace_regrfunc_t r;
226 ptrace_regwfunc_t w;
227
228 #ifdef COMPAT_NETBSD32
229 const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
230
231 if (__predict_false(pk32)) {
232 if ((l->l_proc->p_flag & PK_32) == 0) {
233 // 32 bit tracer can't trace 64 bit process
234 return EINVAL;
235 }
236 s = sizeof(process_fpreg32);
237 r = (ptrace_regrfunc_t)process_read_fpregs32;
238 w = (ptrace_regwfunc_t)process_write_fpregs32;
239 } else
240 #endif
241 {
242 s = sizeof(struct fpreg);
243 r = (ptrace_regrfunc_t)process_read_fpregs;
244 w = (ptrace_regwfunc_t)process_write_fpregs;
245 }
246 return proc_regio(l, uio, s, r, w);
247 #else
248 return EINVAL;
249 #endif
250 }
251
252
253 int
254 process_dodbregs(struct lwp *curl /*tracer*/,
255 struct lwp *l /*traced*/,
256 struct uio *uio)
257 {
258 #if defined(PT_GETDBREGS) || defined(PT_SETDBREGS)
259 size_t s;
260 ptrace_regrfunc_t r;
261 ptrace_regwfunc_t w;
262
263 #ifdef COMPAT_NETBSD32
264 const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
265
266 if (__predict_false(pk32)) {
267 if ((l->l_proc->p_flag & PK_32) == 0) {
268 // 32 bit tracer can't trace 64 bit process
269 return EINVAL;
270 }
271 s = sizeof(process_dbreg32);
272 r = (ptrace_regrfunc_t)process_read_dbregs32;
273 w = (ptrace_regwfunc_t)process_write_dbregs32;
274 } else
275 #endif
276 {
277 s = sizeof(struct dbreg);
278 r = (ptrace_regrfunc_t)process_read_dbregs;
279 w = (ptrace_regwfunc_t)process_write_dbregs;
280 }
281 return proc_regio(l, uio, s, r, w);
282 #else
283 return EINVAL;
284 #endif
285 }
286