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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/uio.h> 31 #include <string.h> 32 #include <errno.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[64]; 72 int fd; 73 74 (void) snprintf(fname, sizeof (fname), "/proc/%d/lwp/%d/%s", 75 (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[64]; 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), "/proc/%d/lwp/%d/lwpctl", 174 (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