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