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