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