9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright 2018 Joyent, Inc.
28 * Copyright (c) 2013 by Delphix. All rights reserved.
29 */
30
31 #include <sys/types.h>
32 #include <sys/uio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <limits.h>
36
37 #include "Pcontrol.h"
38 #include "P32ton.h"
39
40 /*
41 * This file implements the routines to read and write per-lwp register
42 * information from either a live process or core file opened with libproc.
43 * We build up a few common routines for reading and writing register
44 * information, and then the public functions are all trivial calls to these.
45 */
46
47 /*
48 * Utility function to return a pointer to the structure of cached information
49 * about an lwp in the core file, given its lwpid.
50 */
51 static lwp_info_t *
52 getlwpcore(struct ps_prochandle *P, lwpid_t lwpid)
53 {
54 core_info_t *core = P->data;
55 lwp_info_t *lwp;
56
57 for (lwp = list_head(&core->core_lwp_head); lwp != NULL;
58 lwp = list_next(&core->core_lwp_head, lwp)) {
59 if (lwp->lwp_id == lwpid)
60 return (lwp);
61 }
62
63 errno = EINVAL;
64 return (NULL);
65 }
66
67 /*
68 * Utility function to open and read the contents of a per-lwp /proc file.
69 * This function is used to slurp in lwpstatus, xregs, and asrs.
70 */
71 static int
72 getlwpfile(struct ps_prochandle *P, lwpid_t lwpid,
73 const char *fbase, void *rp, size_t n)
74 {
75 char fname[PATH_MAX];
76 int fd;
77
78 (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
79 procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
80
81 if ((fd = open(fname, O_RDONLY)) >= 0) {
82 if (read(fd, rp, n) > 0) {
83 (void) close(fd);
84 return (0);
85 }
86 (void) close(fd);
87 }
88 return (-1);
89 }
90
91 /*
92 * Get the lwpstatus_t for an lwp from either the live process or our
93 * cached information from the core file. This is used to get the
94 * general-purpose registers or floating point registers.
95 */
96 int
97 getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps)
98 {
99 lwp_info_t *lwp;
100
101 /*
102 * For both live processes and cores, our job is easy if the lwpid
103 * matches that of the representative lwp:
104 */
105 if (P->status.pr_lwp.pr_lwpid == lwpid) {
106 (void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t));
107 return (0);
108 }
109
110 /*
111 * If this is a live process, then just read the information out
112 * of the per-lwp status file:
113 */
114 if (P->state != PS_DEAD) {
115 return (getlwpfile(P, lwpid, "lwpstatus",
116 lps, sizeof (lwpstatus_t)));
117 }
118
119 /*
120 * If this is a core file, we need to iterate through our list of
121 * cached lwp information and then copy out the status.
122 */
123 if (P->data != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) {
124 (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t));
125 return (0);
126 }
127
128 return (-1);
129 }
130
131 /*
132 * Utility function to modify lwp registers. This is done using either the
133 * process control file or per-lwp control file as necessary.
134 */
135 static int
136 setlwpregs(struct ps_prochandle *P, lwpid_t lwpid, long cmd,
137 const void *rp, size_t n)
138 {
139 iovec_t iov[2];
140 char fname[PATH_MAX];
141 int fd;
142
143 if (P->state != PS_STOP) {
144 errno = EBUSY;
145 return (-1);
146 }
147
148 iov[0].iov_base = (caddr_t)&cmd;
149 iov[0].iov_len = sizeof (long);
150 iov[1].iov_base = (caddr_t)rp;
151 iov[1].iov_len = n;
152
153 /*
154 * Writing the process control file writes the representative lwp.
155 * Psync before we write to make sure we are consistent with the
156 * primary interfaces. Similarly, make sure to update P->status
157 * afterward if we are modifying one of its register sets.
158 */
159 if (P->status.pr_lwp.pr_lwpid == lwpid) {
160 Psync(P);
161
162 if (writev(P->ctlfd, iov, 2) == -1)
163 return (-1);
164
165 if (cmd == PCSREG)
166 (void) memcpy(P->status.pr_lwp.pr_reg, rp, n);
167 else if (cmd == PCSFPREG)
168 (void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n);
169
170 return (0);
171 }
172
173 /*
174 * If the lwp we want is not the representative lwp, we need to
175 * open the ctl file for that specific lwp.
176 */
177 (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/lwpctl",
178 procfs_path, (int)P->status.pr_pid, (int)lwpid);
179
180 if ((fd = open(fname, O_WRONLY)) >= 0) {
181 if (writev(fd, iov, 2) > 0) {
182 (void) close(fd);
183 return (0);
184 }
185 (void) close(fd);
186 }
187 return (-1);
188 }
189
190 int
191 Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
192 {
193 lwpstatus_t lps;
194
195 if (getlwpstatus(P, lwpid, &lps) == -1)
196 return (-1);
197
198 (void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
199 return (0);
200 }
201
202 int
203 Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
204 {
205 return (setlwpregs(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
206 }
207
208 int
209 Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
210 {
211 lwpstatus_t lps;
212
213 if (getlwpstatus(P, lwpid, &lps) == -1)
214 return (-1);
215
216 (void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
217 return (0);
218 }
219
220 int Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,
221 const prfpregset_t *fpregs)
222 {
223 return (setlwpregs(P, lwpid, PCSFPREG, fpregs, sizeof (prfpregset_t)));
224 }
225
226 #if defined(sparc) || defined(__sparc)
227 int
228 Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t *xregs)
229 {
230 lwp_info_t *lwp;
231
232 if (P->state == PS_IDLE) {
233 errno = ENODATA;
234 return (-1);
235 }
236
237 if (P->state != PS_DEAD) {
238 if (P->state != PS_STOP) {
239 errno = EBUSY;
240 return (-1);
241 }
242
243 return (getlwpfile(P, lwpid, "xregs",
244 xregs, sizeof (prxregset_t)));
245 }
246
247 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL) {
248 (void) memcpy(xregs, lwp->lwp_xregs, sizeof (prxregset_t));
249 return (0);
250 }
251
252 if (lwp != NULL)
253 errno = ENODATA;
254 return (-1);
255 }
256
257 int
258 Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs)
259 {
260 return (setlwpregs(P, lwpid, PCSXREG, xregs, sizeof (prxregset_t)));
261 }
262
263 int
264 Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
265 {
266 lwp_info_t *lwp;
267
268 if (P->state == PS_IDLE) {
269 errno = ENODATA;
270 return (-1);
271 }
272
273 if (P->state != PS_DEAD) {
274 if (P->state != PS_STOP) {
275 errno = EBUSY;
276 return (-1);
277 }
278
279 return (getlwpfile(P, lwpid, "gwindows",
280 gwins, sizeof (gwindows_t)));
281 }
282
283 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {
307 return (-1);
308 }
309
310 return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
311 }
312
313 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
314 (void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
315 return (0);
316 }
317
318 if (lwp != NULL)
319 errno = ENODATA;
320 return (-1);
321
322 }
323
324 int
325 Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
326 {
327 return (setlwpregs(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
328 }
329 #endif /* __sparcv9 */
330 #endif /* __sparc */
331
332 int
333 Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
334 {
335 lwp_info_t *lwp;
336
337 if (P->state == PS_IDLE) {
338 errno = ENODATA;
339 return (-1);
340 }
341
342 if (P->state != PS_DEAD) {
343 return (getlwpfile(P, lwpid, "lwpsinfo",
344 lps, sizeof (lwpsinfo_t)));
345 }
346
347 if ((lwp = getlwpcore(P, lwpid)) != NULL) {
|
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright 2018 Joyent, Inc.
28 * Copyright (c) 2013 by Delphix. All rights reserved.
29 * Copyright 2023 Oxide Computer Company
30 */
31
32 #include <sys/types.h>
33 #include <sys/uio.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <limits.h>
37
38 #include "Pcontrol.h"
39 #include "P32ton.h"
40
41 /*
42 * This file implements the routines to read and write per-lwp register
43 * information from either a live process or core file opened with libproc. We
44 * build up a few common routines for reading and writing register information,
45 * and then the public functions are all trivial calls to these. It also
46 * implements similar logic that is used with an lwp handle.
47 *
48 * The primary registers and floating point registers (e.g. regs,fpregs) are
49 * retreived from the lwp and process status files. The library caches the
50 * values of these files. When we perorm updates, we ensure that cached copies
51 * are refreshed or updated as part of this.
52 */
53
54 /*
55 * Utility function to return a pointer to the structure of cached information
56 * about an lwp in the core file, given its lwpid.
57 */
58 static lwp_info_t *
59 getlwpcore(struct ps_prochandle *P, lwpid_t lwpid)
60 {
61 core_info_t *core = P->data;
62 lwp_info_t *lwp;
63
64 for (lwp = list_head(&core->core_lwp_head); lwp != NULL;
65 lwp = list_next(&core->core_lwp_head, lwp)) {
66 if (lwp->lwp_id == lwpid)
67 return (lwp);
68 }
69
70 errno = ENOENT;
71 return (NULL);
72 }
73
74 /*
75 * Utility function to open and read the contents of a per-lwp /proc file.
76 * This function is used to slurp in lwpstatus, lwpname, lwpsinfo, spymaster,
77 * and others.
78 */
79 static int
80 getlwpfile(struct ps_prochandle *P, lwpid_t lwpid,
81 const char *fbase, void *rp, size_t n)
82 {
83 char fname[PATH_MAX];
84 int fd;
85
86 (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
87 procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
88
89 if ((fd = open(fname, O_RDONLY)) >= 0) {
90 if (read(fd, rp, n) > 0) {
91 (void) close(fd);
92 return (0);
93 }
94
95 int e = errno;
96 (void) close(fd);
97 errno = e;
98 }
99 return (-1);
100 }
101
102 /*
103 * This is a variant of getlwpfile that has three different semantics:
104 *
105 * o It will stat the file to determine the size and allocate that for the
106 * caller.
107 * o If the stat size is zero (e.g. traditional xregs behavior when
108 * unsupported) then it will return the libproc ENODATA error.
109 * o It is an error if not all the data is read.
110 *
111 * Currently this is just used by xregs.
112 */
113 static int
114 getlwpfile_alloc(struct ps_prochandle *P, lwpid_t lwpid, const char *fbase,
115 void **datap, size_t *sizep)
116 {
117 char fname[PATH_MAX];
118 int fd;
119
120 (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
121 procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
122
123 if ((fd = open(fname, O_RDONLY)) >= 0) {
124 int e;
125 struct stat st;
126
127 if (fstat(fd, &st) == 0) {
128 prxregset_t *prx;
129
130 if (st.st_size == 0) {
131 errno = ENODATA;
132 goto clean;
133 }
134
135 prx = malloc(st.st_size);
136 if (prx == NULL) {
137 goto clean;
138 }
139
140 if (read(fd, prx, st.st_size) == st.st_size) {
141 (void) close(fd);
142 *datap = prx;
143 *sizep = st.st_size;
144 return (0);
145 }
146
147 free(prx);
148 }
149 clean:
150 e = errno;
151 (void) close(fd);
152 errno = e;
153 }
154
155 return (-1);
156 }
157
158 /*
159 * Get the lwpstatus_t for an lwp from either the live process or our
160 * cached information from the core file. This is used to get the
161 * general-purpose registers or floating point registers.
162 */
163 int
164 getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps)
165 {
166 lwp_info_t *lwp;
167
168 /*
169 * For both live processes and cores, our job is easy if the lwpid
170 * matches that of the representative lwp:
171 */
172 if (P->status.pr_lwp.pr_lwpid == lwpid) {
173 (void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t));
174 return (0);
175 }
176
177 /*
178 * If this is a live process, then just read the information out
179 * of the per-lwp status file:
180 */
181 if (P->state != PS_DEAD) {
182 return (getlwpfile(P, lwpid, "lwpstatus",
183 lps, sizeof (lwpstatus_t)));
184 }
185
186 /*
187 * If this is a core file, we need to iterate through our list of
188 * cached lwp information and then copy out the status.
189 */
190 if (P->data != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) {
191 (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t));
192 return (0);
193 }
194
195 return (-1);
196 }
197
198 /*
199 * libproc caches information about the registers for representative LWPs and
200 * threads which we have the thread handle for. When we do a write to certain
201 * files, we need to refresh state and take care of both the process and the
202 * representative LWP's info. Because the xregs may or may not mutate the state
203 * of the other regsiters, we just always do a refresh of the entire cached
204 * psinfo.
205 */
206 static void
207 refresh_status(struct ps_prochandle *P, lwpid_t lwpid, struct ps_lwphandle *L,
208 long cmd, const void *rp, size_t n)
209 {
210 if (P->status.pr_lwp.pr_lwpid == lwpid) {
211 if (cmd == PCSREG)
212 (void) memcpy(P->status.pr_lwp.pr_reg, rp, n);
213 else if (cmd == PCSFPREG)
214 (void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n);
215 else if (cmd == PCSXREG)
216 (void) Pstopstatus(P, PCNULL, 0);
217 }
218
219 if (L != NULL) {
220 if (cmd == PCSREG)
221 (void) memcpy(&L->lwp_status.pr_reg, rp, n);
222 else if (cmd == PCSFPREG)
223 (void) memcpy(&L->lwp_status.pr_fpreg, rp, n);
224 else if (cmd == PCSXREG)
225 (void) Lstopstatus(L, PCNULL, 0);
226 }
227 }
228
229 /*
230 * Utility function to modify lwp registers. This is done using either the
231 * process control file or per-lwp control file as necessary. This assumes that
232 * we have a process-level hold on things, which may not always be true.
233 */
234 static int
235 setlwpregs_proc(struct ps_prochandle *P, lwpid_t lwpid, long cmd,
236 const void *rp, size_t n)
237 {
238 iovec_t iov[2];
239 char fname[PATH_MAX];
240 struct ps_lwphandle *L;
241 int fd = -1;
242
243 if (P->state != PS_STOP) {
244 errno = EBUSY;
245 return (-1);
246 }
247
248 iov[0].iov_base = (caddr_t)&cmd;
249 iov[0].iov_len = sizeof (long);
250 iov[1].iov_base = (caddr_t)rp;
251 iov[1].iov_len = n;
252
253 /*
254 * If we have an lwp handle for this thread, then make sure that we use
255 * that to update the state so cached information is updated. We sync
256 * the thread ahead of the process.
257 */
258 if ((L = Lfind(P, lwpid)) != NULL) {
259 Lsync(L);
260 fd = L->lwp_ctlfd;
261 }
262
263 /*
264 * Writing the process control file writes the representative lwp.
265 * Psync before we write to make sure we are consistent with the
266 * primary interfaces. Similarly, make sure to update P->status
267 * afterward if we are modifying one of its register sets. On some
268 * platforms the xregs modify the other register states. As a result,
269 * always refresh the representative LWP's status.
270 */
271 if (P->status.pr_lwp.pr_lwpid == lwpid) {
272 Psync(P);
273 fd = P->ctlfd;
274 }
275
276 if (fd > -1) {
277 if (writev(fd, iov, 2) == -1)
278 return (-1);
279 refresh_status(P, lwpid, L, cmd, rp, n);
280 return (0);
281 }
282
283 /*
284 * If the lwp we want is not the representative lwp, we need to
285 * open the ctl file for that specific lwp.
286 */
287 (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/lwpctl",
288 procfs_path, (int)P->status.pr_pid, (int)lwpid);
289
290 if ((fd = open(fname, O_WRONLY)) >= 0) {
291 if (writev(fd, iov, 2) > 0) {
292 (void) close(fd);
293 return (0);
294 }
295 int e = errno;
296 (void) close(fd);
297 errno = e;
298 }
299 return (-1);
300 }
301
302 /*
303 * This is a variant of the above that only assumes we have a hold on the thread
304 * as opposed to a process.
305 */
306 static int
307 setlwpregs_lwp(struct ps_lwphandle *L, long cmd, const void *rp, size_t n)
308 {
309 iovec_t iov[2];
310
311 if (L->lwp_state != PS_STOP) {
312 errno = EBUSY;
313 return (-1);
314 }
315
316 iov[0].iov_base = (caddr_t)&cmd;
317 iov[0].iov_len = sizeof (long);
318 iov[1].iov_base = (caddr_t)rp;
319 iov[1].iov_len = n;
320
321 Lsync(L);
322 if (writev(L->lwp_ctlfd, iov, 2) == -1)
323 return (-1);
324 refresh_status(L->lwp_proc, L->lwp_id, L, cmd, rp, n);
325
326 return (0);
327 }
328
329 int
330 Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
331 {
332 lwpstatus_t lps;
333
334 if (getlwpstatus(P, lwpid, &lps) == -1)
335 return (-1);
336
337 (void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
338 return (0);
339 }
340
341 int
342 Lgetregs(struct ps_lwphandle *L, prgregset_t *gregs)
343 {
344 (void) memcpy(gregs, L->lwp_status.pr_reg, sizeof (prgregset_t));
345 return (0);
346 }
347
348 int
349 Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
350 {
351 return (setlwpregs_proc(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
352 }
353
354 int
355 Lsetregs(struct ps_lwphandle *L, const prgregset_t *gregs)
356 {
357 return (setlwpregs_lwp(L, PCSREG, gregs, sizeof (prgregset_t)));
358 }
359
360 int
361 Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
362 {
363 lwpstatus_t lps;
364
365 if (getlwpstatus(P, lwpid, &lps) == -1)
366 return (-1);
367
368 (void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
369 return (0);
370 }
371
372 int
373 Lgetfpregs(struct ps_lwphandle *L, prfpregset_t *fpregs)
374 {
375 (void) memcpy(fpregs, &L->lwp_status.pr_fpreg, sizeof (prfpregset_t));
376 return (0);
377 }
378
379 int
380 Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,
381 const prfpregset_t *fpregs)
382 {
383 return (setlwpregs_proc(P, lwpid, PCSFPREG, fpregs,
384 sizeof (prfpregset_t)));
385 }
386
387 int
388 Lsetfpregs(struct ps_lwphandle *L, const prfpregset_t *fpregs)
389 {
390 return (setlwpregs_lwp(L, PCSFPREG, fpregs, sizeof (prfpregset_t)));
391 }
392
393 /*
394 * The reason that this is structured to take both the size and the process
395 * handle is so that way we have enough information to tie this back to its
396 * underlying source and we can eventually use umem with this.
397 */
398 void
399 Plwp_freexregs(struct ps_prochandle *P __unused, prxregset_t *prx,
400 size_t size __unused)
401 {
402 free(prx);
403 }
404
405 int
406 Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t **xregs,
407 size_t *sizep)
408 {
409 lwp_info_t *lwp;
410
411 if (P->state == PS_IDLE) {
412 errno = ENODATA;
413 return (-1);
414 }
415
416 if (P->state != PS_DEAD) {
417 if (P->state != PS_STOP) {
418 errno = EBUSY;
419 return (-1);
420 }
421
422 return (getlwpfile_alloc(P, lwpid, "xregs",
423 (void **)xregs, sizep));
424 }
425
426 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL &&
427 lwp->lwp_xregsize > 0) {
428 *xregs = malloc(lwp->lwp_xregsize);
429 if (*xregs == NULL)
430 return (-1);
431 (void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
432 *sizep = lwp->lwp_xregsize;
433 return (0);
434 }
435
436 if (lwp != NULL)
437 errno = ENODATA;
438 return (-1);
439 }
440
441 int
442 Lgetxregs(struct ps_lwphandle *L, prxregset_t **xregs, size_t *sizep)
443 {
444 lwp_info_t *lwp;
445
446 if (L->lwp_state != PS_DEAD) {
447 if (L->lwp_state != PS_STOP) {
448 errno = EBUSY;
449 return (-1);
450 }
451 return (getlwpfile_alloc(L->lwp_proc, L->lwp_id, "xregs",
452 (void **)xregs, sizep));
453 }
454
455 if ((lwp = getlwpcore(L->lwp_proc, L->lwp_id)) != NULL &&
456 lwp->lwp_xregs != NULL && lwp->lwp_xregsize > 0) {
457 *xregs = malloc(lwp->lwp_xregsize);
458 if (*xregs == NULL)
459 return (-1);
460 (void) memcpy(*xregs, lwp->lwp_xregs, lwp->lwp_xregsize);
461 *sizep = lwp->lwp_xregsize;
462 return (0);
463 }
464
465 if (lwp != NULL)
466 errno = ENODATA;
467 return (-1);
468 }
469
470 int
471 Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs,
472 size_t len)
473 {
474 return (setlwpregs_proc(P, lwpid, PCSXREG, xregs, len));
475 }
476
477 int
478 Lsetxregs(struct ps_lwphandle *L, const prxregset_t *xregs, size_t len)
479 {
480 return (setlwpregs_lwp(L, PCSXREG, xregs, len));
481 }
482
483 #if defined(sparc) || defined(__sparc)
484 int
485 Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
486 {
487 lwp_info_t *lwp;
488
489 if (P->state == PS_IDLE) {
490 errno = ENODATA;
491 return (-1);
492 }
493
494 if (P->state != PS_DEAD) {
495 if (P->state != PS_STOP) {
496 errno = EBUSY;
497 return (-1);
498 }
499
500 return (getlwpfile(P, lwpid, "gwindows",
501 gwins, sizeof (gwindows_t)));
502 }
503
504 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {
528 return (-1);
529 }
530
531 return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
532 }
533
534 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
535 (void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
536 return (0);
537 }
538
539 if (lwp != NULL)
540 errno = ENODATA;
541 return (-1);
542
543 }
544
545 int
546 Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
547 {
548 return (setlwpregs_proc(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
549 }
550 #endif /* __sparcv9 */
551 #endif /* __sparc */
552
553 int
554 Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
555 {
556 lwp_info_t *lwp;
557
558 if (P->state == PS_IDLE) {
559 errno = ENODATA;
560 return (-1);
561 }
562
563 if (P->state != PS_DEAD) {
564 return (getlwpfile(P, lwpid, "lwpsinfo",
565 lps, sizeof (lwpsinfo_t)));
566 }
567
568 if ((lwp = getlwpcore(P, lwpid)) != NULL) {
|