xref: /illumos-gate/usr/src/lib/libproc/common/Plwpregs.c (revision 7957df47ba71407f1d0517aa3f34f1bdde135b84)
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 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) {
284 		*gwins = *lwp->lwp_gwins;
285 		return (0);
286 	}
287 
288 	if (lwp != NULL)
289 		errno = ENODATA;
290 	return (-1);
291 }
292 
293 #if defined(__sparcv9)
294 int
295 Plwp_getasrs(struct ps_prochandle *P, lwpid_t lwpid, asrset_t asrs)
296 {
297 	lwp_info_t *lwp;
298 
299 	if (P->state == PS_IDLE) {
300 		errno = ENODATA;
301 		return (-1);
302 	}
303 
304 	if (P->state != PS_DEAD) {
305 		if (P->state != PS_STOP) {
306 			errno = EBUSY;
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) {
348 		(void) memcpy(lps, &lwp->lwp_psinfo, sizeof (lwpsinfo_t));
349 		return (0);
350 	}
351 
352 	return (-1);
353 }
354 
355 int
356 Plwp_getname(struct ps_prochandle *P, lwpid_t lwpid,
357     char *buf, size_t bufsize)
358 {
359 	char lwpname[THREAD_NAME_MAX];
360 	char *from = NULL;
361 	lwp_info_t *lwp;
362 
363 	if (P->state == PS_IDLE) {
364 		errno = ENODATA;
365 		return (-1);
366 	}
367 
368 	if (P->state != PS_DEAD) {
369 		if (getlwpfile(P, lwpid, "lwpname",
370 		    lwpname, sizeof (lwpname)) != 0)
371 			return (-1);
372 		from = lwpname;
373 	} else {
374 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
375 			return (-1);
376 		from = lwp->lwp_name;
377 	}
378 
379 	if (strlcpy(buf, from, bufsize) >= bufsize) {
380 		errno = ENAMETOOLONG;
381 		return (-1);
382 	}
383 
384 	return (0);
385 }
386 
387 int
388 Plwp_getspymaster(struct ps_prochandle *P, lwpid_t lwpid, psinfo_t *ps)
389 {
390 	lwpstatus_t lps;
391 
392 	if (P->state == PS_IDLE) {
393 		errno = ENODATA;
394 		return (-1);
395 	}
396 
397 	if (getlwpstatus(P, lwpid, &lps) != 0)
398 		return (-1);
399 
400 	if (!(lps.pr_flags & PR_AGENT)) {
401 		errno = EINVAL;
402 		return (-1);
403 	}
404 
405 	if (P->state != PS_DEAD) {
406 		return (getlwpfile(P, lwpid, "spymaster",
407 		    ps, sizeof (psinfo_t)));
408 	}
409 
410 	if (P->spymaster.pr_nlwp != 0) {
411 		(void) memcpy(ps, &P->spymaster, sizeof (psinfo_t));
412 		return (0);
413 	}
414 
415 	errno = ENODATA;
416 
417 	return (-1);
418 }
419 
420 int
421 Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
422 {
423 	uintptr_t addr;
424 
425 	if (P->state == PS_IDLE) {
426 		errno = ENODATA;
427 		return (-1);
428 	}
429 
430 	if (P->state != PS_DEAD) {
431 		lwpstatus_t ls;
432 		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
433 			return (-1);
434 		addr = ls.pr_ustack;
435 	} else {
436 		lwp_info_t *lwp;
437 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
438 			return (-1);
439 		addr = lwp->lwp_status.pr_ustack;
440 	}
441 
442 
443 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
444 		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
445 			return (-1);
446 #ifdef _LP64
447 	} else {
448 		stack32_t stk32;
449 
450 		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
451 			return (-1);
452 
453 		stack_32_to_n(&stk32, stkp);
454 #endif
455 	}
456 
457 	return (0);
458 }
459 
460 int
461 Plwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
462 {
463 	uintptr_t addr;
464 	lwpstatus_t ls;
465 
466 	if (P->state == PS_IDLE) {
467 		errno = ENODATA;
468 		return (-1);
469 	}
470 
471 	if (P->state != PS_DEAD) {
472 		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
473 			return (-1);
474 	} else {
475 		lwp_info_t *lwp;
476 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
477 			return (-1);
478 		ls = lwp->lwp_status;
479 	}
480 
481 	addr = ls.pr_ustack;
482 
483 	/*
484 	 * Read out the current stack; if the SS_ONSTACK flag is set then
485 	 * this LWP is operating on the alternate signal stack. We can
486 	 * recover the original stack from pr_oldcontext.
487 	 */
488 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
489 		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
490 			return (-1);
491 
492 		if (stkp->ss_flags & SS_ONSTACK)
493 			goto on_altstack;
494 #ifdef _LP64
495 	} else {
496 		stack32_t stk32;
497 
498 		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
499 			return (-1);
500 
501 		if (stk32.ss_flags & SS_ONSTACK)
502 			goto on_altstack;
503 
504 		stack_32_to_n(&stk32, stkp);
505 #endif
506 	}
507 
508 	return (0);
509 
510 on_altstack:
511 
512 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
513 		ucontext_t *ctxp = (void *)ls.pr_oldcontext;
514 
515 		if (Pread(P, stkp, sizeof (*stkp),
516 		    (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
517 			return (-1);
518 #ifdef _LP64
519 	} else {
520 		ucontext32_t *ctxp = (void *)ls.pr_oldcontext;
521 		stack32_t stk32;
522 
523 		if (Pread(P, &stk32, sizeof (stk32),
524 		    (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
525 			return (-1);
526 
527 		stack_32_to_n(&stk32, stkp);
528 #endif
529 	}
530 
531 	return (0);
532 }
533 
534 int
535 Plwp_alt_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
536 {
537 	if (P->state == PS_IDLE) {
538 		errno = ENODATA;
539 		return (-1);
540 	}
541 
542 	if (P->state != PS_DEAD) {
543 		lwpstatus_t ls;
544 
545 		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
546 			return (-1);
547 
548 		if (ls.pr_altstack.ss_flags & SS_DISABLE) {
549 			errno = ENODATA;
550 			return (-1);
551 		}
552 
553 		*stkp = ls.pr_altstack;
554 	} else {
555 		lwp_info_t *lwp;
556 
557 		if ((lwp = getlwpcore(P, lwpid)) == NULL)
558 			return (-1);
559 
560 		if (lwp->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
561 			errno = ENODATA;
562 			return (-1);
563 		}
564 
565 		*stkp = lwp->lwp_status.pr_altstack;
566 	}
567 
568 	return (0);
569 }
570