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 *
getlwpcore(struct ps_prochandle * P,lwpid_t lwpid)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
getlwpfile(struct ps_prochandle * P,lwpid_t lwpid,const char * fbase,void * rp,size_t n)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
getlwpstatus(struct ps_prochandle * P,lwpid_t lwpid,lwpstatus_t * lps)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
setlwpregs(struct ps_prochandle * P,lwpid_t lwpid,long cmd,const void * rp,size_t n)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
Plwp_getregs(struct ps_prochandle * P,lwpid_t lwpid,prgregset_t gregs)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
Plwp_setregs(struct ps_prochandle * P,lwpid_t lwpid,const prgregset_t gregs)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
Plwp_getfpregs(struct ps_prochandle * P,lwpid_t lwpid,prfpregset_t * fpregs)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
Plwp_setfpregs(struct ps_prochandle * P,lwpid_t lwpid,const prfpregset_t * fpregs)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
Plwp_getxregs(struct ps_prochandle * P,lwpid_t lwpid,prxregset_t * xregs)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
Plwp_setxregs(struct ps_prochandle * P,lwpid_t lwpid,const prxregset_t * xregs)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
Plwp_getgwindows(struct ps_prochandle * P,lwpid_t lwpid,gwindows_t * gwins)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
Plwp_getasrs(struct ps_prochandle * P,lwpid_t lwpid,asrset_t asrs)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
Plwp_setasrs(struct ps_prochandle * P,lwpid_t lwpid,const asrset_t asrs)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
Plwp_getpsinfo(struct ps_prochandle * P,lwpid_t lwpid,lwpsinfo_t * lps)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
Plwp_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)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
Plwp_main_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)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
Plwp_alt_stack(struct ps_prochandle * P,lwpid_t lwpid,stack_t * stkp)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