sys_process_lwpstatus.c revision 1.5 1 1.5 christos /* $NetBSD: sys_process_lwpstatus.c,v 1.5 2025/01/11 19:42:04 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.5 christos __KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.5 2025/01/11 19:42:04 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.3 rin #include <sys/proc.h>
49 1.1 kamil #include <sys/ptrace.h>
50 1.1 kamil
51 1.2 christos #ifndef PTRACE_REGS_ALIGN
52 1.2 christos #define PTRACE_REGS_ALIGN /* nothing */
53 1.2 christos #endif
54 1.1 kamil
55 1.1 kamil void
56 1.1 kamil ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
57 1.1 kamil {
58 1.1 kamil
59 1.4 riastrad pls->pl_lwpid = l->l_lid;
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 ptrace_read_lwpstatus(l, pls);
82 1.1 kamil }
83 1.2 christos
84 1.2 christos int
85 1.2 christos ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid)
86 1.2 christos {
87 1.2 christos if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
88 1.2 christos return 0;
89 1.2 christos
90 1.2 christos mutex_enter(t->p_lock);
91 1.2 christos lwp_delref2(*lt);
92 1.2 christos
93 1.2 christos *lt = lwp_find(t, lid);
94 1.2 christos if (*lt == NULL) {
95 1.2 christos mutex_exit(t->p_lock);
96 1.2 christos return ESRCH;
97 1.2 christos }
98 1.2 christos
99 1.2 christos if ((*lt)->l_flag & LW_SYSTEM) {
100 1.2 christos mutex_exit(t->p_lock);
101 1.2 christos *lt = NULL;
102 1.2 christos return EINVAL;
103 1.2 christos }
104 1.2 christos
105 1.2 christos lwp_addref(*lt);
106 1.2 christos mutex_exit(t->p_lock);
107 1.2 christos
108 1.2 christos return 0;
109 1.2 christos }
110 1.2 christos
111 1.2 christos int
112 1.2 christos process_validfpregs(struct lwp *l)
113 1.2 christos {
114 1.2 christos
115 1.5 christos #if defined(PT_FPREGS)
116 1.2 christos return (l->l_flag & LW_SYSTEM) == 0;
117 1.2 christos #else
118 1.2 christos return 0;
119 1.2 christos #endif
120 1.2 christos }
121 1.2 christos
122 1.2 christos int
123 1.2 christos process_validregs(struct lwp *l)
124 1.2 christos {
125 1.2 christos
126 1.5 christos #if defined(PT_REGS)
127 1.2 christos return (l->l_flag & LW_SYSTEM) == 0;
128 1.2 christos #else
129 1.2 christos return 0;
130 1.2 christos #endif
131 1.2 christos }
132 1.2 christos
133 1.2 christos int
134 1.2 christos process_validdbregs(struct lwp *l)
135 1.2 christos {
136 1.2 christos
137 1.5 christos #if defined(PT_DBREGS)
138 1.2 christos return (l->l_flag & LW_SYSTEM) == 0;
139 1.2 christos #else
140 1.2 christos return 0;
141 1.2 christos #endif
142 1.2 christos }
143 1.2 christos
144 1.2 christos #ifdef PT_REGISTERS
145 1.2 christos static int
146 1.2 christos proc_regio(struct lwp *l, struct uio *uio, size_t ks, ptrace_regrfunc_t r,
147 1.2 christos ptrace_regwfunc_t w)
148 1.2 christos {
149 1.2 christos char buf[1024] PTRACE_REGS_ALIGN;
150 1.2 christos int error;
151 1.2 christos char *kv;
152 1.2 christos size_t kl;
153 1.2 christos
154 1.2 christos if (ks > sizeof(buf))
155 1.2 christos return E2BIG;
156 1.2 christos
157 1.2 christos if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks)
158 1.2 christos return EINVAL;
159 1.2 christos
160 1.2 christos kv = buf + uio->uio_offset;
161 1.2 christos kl = ks - uio->uio_offset;
162 1.2 christos
163 1.2 christos if (kl > uio->uio_resid)
164 1.2 christos kl = uio->uio_resid;
165 1.2 christos
166 1.2 christos error = (*r)(l, buf, &ks);
167 1.2 christos if (error == 0)
168 1.2 christos error = uiomove(kv, kl, uio);
169 1.2 christos if (error == 0 && uio->uio_rw == UIO_WRITE) {
170 1.2 christos if (l->l_stat != LSSTOP)
171 1.2 christos error = EBUSY;
172 1.2 christos else
173 1.2 christos error = (*w)(l, buf, ks);
174 1.2 christos }
175 1.2 christos
176 1.2 christos uio->uio_offset = 0;
177 1.2 christos return error;
178 1.2 christos }
179 1.2 christos #endif
180 1.2 christos
181 1.2 christos int
182 1.2 christos process_doregs(struct lwp *curl /*tracer*/,
183 1.2 christos struct lwp *l /*traced*/,
184 1.2 christos struct uio *uio)
185 1.2 christos {
186 1.5 christos #if defined(PT_REGS)
187 1.2 christos size_t s;
188 1.2 christos ptrace_regrfunc_t r;
189 1.2 christos ptrace_regwfunc_t w;
190 1.2 christos
191 1.2 christos #ifdef COMPAT_NETBSD32
192 1.2 christos const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
193 1.2 christos
194 1.2 christos if (__predict_false(pk32)) {
195 1.2 christos if ((l->l_proc->p_flag & PK_32) == 0) {
196 1.2 christos // 32 bit tracer can't trace 64 bit process
197 1.2 christos return EINVAL;
198 1.2 christos }
199 1.2 christos s = sizeof(process_reg32);
200 1.2 christos r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs32);
201 1.2 christos w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs32);
202 1.2 christos } else
203 1.2 christos #endif
204 1.2 christos {
205 1.2 christos s = sizeof(struct reg);
206 1.2 christos r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs);
207 1.2 christos w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs);
208 1.2 christos }
209 1.2 christos return proc_regio(l, uio, s, r, w);
210 1.2 christos #else
211 1.2 christos return EINVAL;
212 1.2 christos #endif
213 1.2 christos }
214 1.2 christos
215 1.2 christos int
216 1.2 christos process_dofpregs(struct lwp *curl /*tracer*/,
217 1.2 christos struct lwp *l /*traced*/,
218 1.2 christos struct uio *uio)
219 1.2 christos {
220 1.5 christos #if defined(PT_FPREGS)
221 1.2 christos size_t s;
222 1.2 christos ptrace_regrfunc_t r;
223 1.2 christos ptrace_regwfunc_t w;
224 1.2 christos
225 1.2 christos #ifdef COMPAT_NETBSD32
226 1.2 christos const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
227 1.2 christos
228 1.2 christos if (__predict_false(pk32)) {
229 1.2 christos if ((l->l_proc->p_flag & PK_32) == 0) {
230 1.2 christos // 32 bit tracer can't trace 64 bit process
231 1.2 christos return EINVAL;
232 1.2 christos }
233 1.2 christos s = sizeof(process_fpreg32);
234 1.2 christos r = (ptrace_regrfunc_t)process_read_fpregs32;
235 1.2 christos w = (ptrace_regwfunc_t)process_write_fpregs32;
236 1.2 christos } else
237 1.2 christos #endif
238 1.2 christos {
239 1.2 christos s = sizeof(struct fpreg);
240 1.2 christos r = (ptrace_regrfunc_t)process_read_fpregs;
241 1.2 christos w = (ptrace_regwfunc_t)process_write_fpregs;
242 1.2 christos }
243 1.2 christos return proc_regio(l, uio, s, r, w);
244 1.2 christos #else
245 1.2 christos return EINVAL;
246 1.2 christos #endif
247 1.2 christos }
248 1.2 christos
249 1.2 christos
250 1.2 christos int
251 1.2 christos process_dodbregs(struct lwp *curl /*tracer*/,
252 1.2 christos struct lwp *l /*traced*/,
253 1.2 christos struct uio *uio)
254 1.2 christos {
255 1.5 christos #if defined(PT_DBREGS)
256 1.2 christos size_t s;
257 1.2 christos ptrace_regrfunc_t r;
258 1.2 christos ptrace_regwfunc_t w;
259 1.2 christos
260 1.2 christos #ifdef COMPAT_NETBSD32
261 1.2 christos const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
262 1.2 christos
263 1.2 christos if (__predict_false(pk32)) {
264 1.2 christos if ((l->l_proc->p_flag & PK_32) == 0) {
265 1.2 christos // 32 bit tracer can't trace 64 bit process
266 1.2 christos return EINVAL;
267 1.2 christos }
268 1.2 christos s = sizeof(process_dbreg32);
269 1.2 christos r = (ptrace_regrfunc_t)process_read_dbregs32;
270 1.2 christos w = (ptrace_regwfunc_t)process_write_dbregs32;
271 1.2 christos } else
272 1.2 christos #endif
273 1.2 christos {
274 1.2 christos s = sizeof(struct dbreg);
275 1.2 christos r = (ptrace_regrfunc_t)process_read_dbregs;
276 1.2 christos w = (ptrace_regwfunc_t)process_write_dbregs;
277 1.2 christos }
278 1.2 christos return proc_regio(l, uio, s, r, w);
279 1.2 christos #else
280 1.2 christos return EINVAL;
281 1.2 christos #endif
282 1.2 christos }
283