XXX AVX procfs
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
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 #include <sys/types.h>
27 #include <sys/uio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <limits.h>
31
32 #include "Pcontrol.h"
33 #include "P32ton.h"
34
35 /*
36 * This file implements the routines to read and write per-lwp register
37 * information from either a live process or core file opened with libproc.
38 * We build up a few common routines for reading and writing register
39 * information, and then the public functions are all trivial calls to these.
40 */
41
42 /*
43 * Utility function to return a pointer to the structure of cached information
44 * about an lwp in the core file, given its lwpid.
45 */
46 static lwp_info_t *
47 getlwpcore(struct ps_prochandle *P, lwpid_t lwpid)
48 {
49 lwp_info_t *lwp = list_next(&P->core->core_lwp_head);
50 uint_t i;
51
52 for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) {
53 if (lwp->lwp_id == lwpid)
54 return (lwp);
55 }
56
57 errno = EINVAL;
58 return (NULL);
59 }
60
61 /*
62 * Utility function to open and read the contents of a per-lwp /proc file.
63 * This function is used to slurp in lwpstatus, xregs, and asrs.
64 */
65 static int
66 getlwpfile(struct ps_prochandle *P, lwpid_t lwpid,
67 const char *fbase, void *rp, size_t n)
68 {
69 char fname[PATH_MAX];
70 int fd;
71
72 (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/%s",
73 procfs_path, (int)P->status.pr_pid, (int)lwpid, fbase);
74
75 if ((fd = open(fname, O_RDONLY)) >= 0) {
76 if (read(fd, rp, n) > 0) {
77 (void) close(fd);
78 return (0);
79 }
80 (void) close(fd);
81 }
82 return (-1);
83 }
84
85 /*
86 * Get the lwpstatus_t for an lwp from either the live process or our
87 * cached information from the core file. This is used to get the
88 * general-purpose registers or floating point registers.
89 */
90 int
91 getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps)
92 {
93 lwp_info_t *lwp;
94
95 /*
96 * For both live processes and cores, our job is easy if the lwpid
97 * matches that of the representative lwp:
98 */
99 if (P->status.pr_lwp.pr_lwpid == lwpid) {
100 (void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t));
101 return (0);
102 }
103
104 /*
105 * If this is a live process, then just read the information out
106 * of the per-lwp status file:
107 */
108 if (P->state != PS_DEAD) {
109 return (getlwpfile(P, lwpid, "lwpstatus",
110 lps, sizeof (lwpstatus_t)));
111 }
112
113 /*
114 * If this is a core file, we need to iterate through our list of
115 * cached lwp information and then copy out the status.
116 */
117 if (P->core != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) {
118 (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t));
119 return (0);
120 }
121
122 return (-1);
123 }
124
125 /*
126 * Utility function to modify lwp registers. This is done using either the
127 * process control file or per-lwp control file as necessary.
128 */
129 static int
130 setlwpregs(struct ps_prochandle *P, lwpid_t lwpid, long cmd,
131 const void *rp, size_t n)
132 {
133 iovec_t iov[2];
134 char fname[PATH_MAX];
135 int fd;
136
137 if (P->state != PS_STOP) {
138 errno = EBUSY;
139 return (-1);
140 }
141
142 iov[0].iov_base = (caddr_t)&cmd;
143 iov[0].iov_len = sizeof (long);
144 iov[1].iov_base = (caddr_t)rp;
145 iov[1].iov_len = n;
146
147 /*
148 * Writing the process control file writes the representative lwp.
149 * Psync before we write to make sure we are consistent with the
150 * primary interfaces. Similarly, make sure to update P->status
151 * afterward if we are modifying one of its register sets.
152 */
153 if (P->status.pr_lwp.pr_lwpid == lwpid) {
154 Psync(P);
155
156 if (writev(P->ctlfd, iov, 2) == -1)
157 return (-1);
158
159 if (cmd == PCSREG)
160 (void) memcpy(P->status.pr_lwp.pr_reg, rp, n);
161 else if (cmd == PCSFPREG)
162 (void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n);
163
164 return (0);
165 }
166
167 /*
168 * If the lwp we want is not the representative lwp, we need to
169 * open the ctl file for that specific lwp.
170 */
171 (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/lwpctl",
172 procfs_path, (int)P->status.pr_pid, (int)lwpid);
173
174 if ((fd = open(fname, O_WRONLY)) >= 0) {
175 if (writev(fd, iov, 2) > 0) {
176 (void) close(fd);
177 return (0);
178 }
179 (void) close(fd);
180 }
181 return (-1);
182 }
183
184 int
185 Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
186 {
187 lwpstatus_t lps;
188
189 if (getlwpstatus(P, lwpid, &lps) == -1)
190 return (-1);
191
192 (void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
193 return (0);
194 }
195
196 int
197 Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
198 {
199 return (setlwpregs(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
200 }
201
202 int
203 Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
204 {
205 lwpstatus_t lps;
206
207 if (getlwpstatus(P, lwpid, &lps) == -1)
208 return (-1);
209
210 (void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
211 return (0);
212 }
213
214 int Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,
215 const prfpregset_t *fpregs)
216 {
217 return (setlwpregs(P, lwpid, PCSFPREG, fpregs, sizeof (prfpregset_t)));
218 }
219
220 int
221 Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t *xregs)
222 {
223 lwp_info_t *lwp;
224
225 if (P->state == PS_IDLE) {
226 errno = ENODATA;
227 return (-1);
228 }
229
230 if (P->state != PS_DEAD) {
231 if (P->state != PS_STOP) {
232 errno = EBUSY;
233 return (-1);
234 }
235
236 return (getlwpfile(P, lwpid, "xregs",
237 xregs, sizeof (prxregset_t)));
238 }
239
240 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL) {
241 (void) memcpy(xregs, lwp->lwp_xregs, sizeof (prxregset_t));
242 return (0);
243 }
244
245 if (lwp != NULL)
246 errno = ENODATA;
247 return (-1);
248 }
249
250 int
251 Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs)
252 {
253 return (setlwpregs(P, lwpid, PCSXREG, xregs, sizeof (prxregset_t)));
254 }
255
256 #if defined(sparc) || defined(__sparc)
257 int
258 Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
259 {
260 lwp_info_t *lwp;
261
262 if (P->state == PS_IDLE) {
263 errno = ENODATA;
264 return (-1);
265 }
266
267 if (P->state != PS_DEAD) {
268 if (P->state != PS_STOP) {
269 errno = EBUSY;
270 return (-1);
271 }
272
273 return (getlwpfile(P, lwpid, "gwindows",
274 gwins, sizeof (gwindows_t)));
275 }
276
277 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {
278 *gwins = *lwp->lwp_gwins;
279 return (0);
280 }
281
282 if (lwp != NULL)
283 errno = ENODATA;
284 return (-1);
285 }
286
287 #if defined(__sparcv9)
288 int
289 Plwp_getasrs(struct ps_prochandle *P, lwpid_t lwpid, asrset_t asrs)
290 {
291 lwp_info_t *lwp;
292
293 if (P->state == PS_IDLE) {
294 errno = ENODATA;
295 return (-1);
296 }
297
298 if (P->state != PS_DEAD) {
299 if (P->state != PS_STOP) {
300 errno = EBUSY;
301 return (-1);
302 }
303
304 return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
305 }
306
307 if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
308 (void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
309 return (0);
310 }
311
312 if (lwp != NULL)
313 errno = ENODATA;
314 return (-1);
315
316 }
317
318 int
319 Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
320 {
321 return (setlwpregs(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
322 }
323 #endif /* __sparcv9 */
324 #endif /* __sparc */
325
326 int
327 Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
328 {
329 lwp_info_t *lwp;
330
331 if (P->state == PS_IDLE) {
332 errno = ENODATA;
333 return (-1);
334 }
335
336 if (P->state != PS_DEAD) {
337 return (getlwpfile(P, lwpid, "lwpsinfo",
338 lps, sizeof (lwpsinfo_t)));
339 }
340
341 if ((lwp = getlwpcore(P, lwpid)) != NULL) {
342 (void) memcpy(lps, &lwp->lwp_psinfo, sizeof (lwpsinfo_t));
343 return (0);
344 }
345
346 return (-1);
347 }
348
349 int
350 Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
351 {
352 uintptr_t addr;
353
354 if (P->state == PS_IDLE) {
355 errno = ENODATA;
356 return (-1);
357 }
358
359 if (P->state != PS_DEAD) {
360 lwpstatus_t ls;
361 if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
362 return (-1);
363 addr = ls.pr_ustack;
364 } else {
365 lwp_info_t *lwp;
366 if ((lwp = getlwpcore(P, lwpid)) == NULL)
367 return (-1);
368 addr = lwp->lwp_status.pr_ustack;
369 }
370
371
372 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
373 if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
374 return (-1);
375 #ifdef _LP64
376 } else {
377 stack32_t stk32;
378
379 if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
380 return (-1);
381
382 stack_32_to_n(&stk32, stkp);
383 #endif
384 }
385
386 return (0);
387 }
388
389 int
390 Plwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
391 {
392 uintptr_t addr;
393 lwpstatus_t ls;
394
395 if (P->state == PS_IDLE) {
396 errno = ENODATA;
397 return (-1);
398 }
399
400 if (P->state != PS_DEAD) {
401 if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
402 return (-1);
403 } else {
404 lwp_info_t *lwp;
405 if ((lwp = getlwpcore(P, lwpid)) == NULL)
406 return (-1);
407 ls = lwp->lwp_status;
408 }
409
410 addr = ls.pr_ustack;
411
412 /*
413 * Read out the current stack; if the SS_ONSTACK flag is set then
414 * this LWP is operating on the alternate signal stack. We can
415 * recover the original stack from pr_oldcontext.
416 */
417 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
418 if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
419 return (-1);
420
421 if (stkp->ss_flags & SS_ONSTACK)
422 goto on_altstack;
423 #ifdef _LP64
424 } else {
425 stack32_t stk32;
426
427 if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
428 return (-1);
429
430 if (stk32.ss_flags & SS_ONSTACK)
431 goto on_altstack;
432
433 stack_32_to_n(&stk32, stkp);
434 #endif
435 }
436
437 return (0);
438
439 on_altstack:
440
441 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
442 ucontext_t *ctxp = (void *)ls.pr_oldcontext;
443
444 if (Pread(P, stkp, sizeof (*stkp),
445 (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
446 return (-1);
447 #ifdef _LP64
448 } else {
449 ucontext32_t *ctxp = (void *)ls.pr_oldcontext;
450 stack32_t stk32;
451
452 if (Pread(P, &stk32, sizeof (stk32),
453 (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
454 return (-1);
455
456 stack_32_to_n(&stk32, stkp);
457 #endif
458 }
459
460 return (0);
461 }
462
463 int
464 Plwp_alt_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
465 {
466 if (P->state == PS_IDLE) {
467 errno = ENODATA;
468 return (-1);
469 }
470
471 if (P->state != PS_DEAD) {
472 lwpstatus_t ls;
473
474 if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
475 return (-1);
476
477 if (ls.pr_altstack.ss_flags & SS_DISABLE) {
478 errno = ENODATA;
479 return (-1);
480 }
481
482 *stkp = ls.pr_altstack;
483 } else {
484 lwp_info_t *lwp;
485
486 if ((lwp = getlwpcore(P, lwpid)) == NULL)
487 return (-1);
488
489 if (lwp->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
490 errno = ENODATA;
491 return (-1);
492 }
493
494 *stkp = lwp->lwp_status.pr_altstack;
495 }
496
497 return (0);
498 }
--- EOF ---