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