Print this page
    
15254 %ymm registers not restored after signal handler
15367 x86 getfpregs() summons corrupting %xmm ghosts
15333 want x86 /proc xregs support (libc_db, libproc, mdb, etc.)
15336 want libc functions for extended ucontext_t
15334 want ps_lwphandle-specific reg routines
15328 FPU_CW_INIT mistreats reserved bit
15335 i86pc fpu_subr.c isn't really platform-specific
15332 setcontext(2) isn't actually noreturn
15331 need <sys/stdalign.h>
Change-Id: I7060aa86042dfb989f77fc3323c065ea2eafa9ad
Conflicts:
    usr/src/uts/common/fs/proc/prcontrol.c
    usr/src/uts/intel/os/archdep.c
    usr/src/uts/intel/sys/ucontext.h
    usr/src/uts/intel/syscall/getcontext.c
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libproc/common/Pservice.c
          +++ new/usr/src/lib/libproc/common/Pservice.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  /*
  26   26   * Copyright (c) 2013 by Delphix. All rights reserved.
       27 + * Copyright 2023 Oxide Computer Company
  27   28   */
  28   29  
  29   30  #include <stdarg.h>
  30   31  #include <string.h>
       32 +#include <errno.h>
  31   33  #include "Pcontrol.h"
  32   34  
  33   35  /*
  34   36   * This file implements the process services declared in <proc_service.h>.
  35   37   * This enables libproc to be used in conjunction with libc_db and
  36   38   * librtld_db.  As most of these facilities are already provided by
  37   39   * (more elegant) interfaces in <libproc.h>, we can just call those.
  38   40   *
  39   41   * NOTE: We explicitly do *not* implement the functions ps_kill() and
  40   42   * ps_lrolltoaddr() in this library.  The very existence of these functions
  41   43   * causes libc_db to create an "agent thread" in the target process.
  42   44   * The only way to turn off this behavior is to omit these functions.
  43   45   */
  44   46  
  45   47  #pragma weak ps_pdread = ps_pread
  46   48  #pragma weak ps_ptread = ps_pread
  47   49  #pragma weak ps_pdwrite = ps_pwrite
  48   50  #pragma weak ps_ptwrite = ps_pwrite
  49   51  
  50   52  ps_err_e
  51   53  ps_pdmodel(struct ps_prochandle *P, int *modelp)
  52   54  {
  53   55          *modelp = P->status.pr_dmodel;
  54   56          return (PS_OK);
  55   57  }
  56   58  
  57   59  ps_err_e
  58   60  ps_pread(struct ps_prochandle *P, psaddr_t addr, void *buf, size_t size)
  59   61  {
  60   62          if (P->ops.pop_pread(P, buf, size, addr, P->data) != size)
  61   63                  return (PS_BADADDR);
  62   64          return (PS_OK);
  63   65  }
  64   66  
  65   67  ps_err_e
  66   68  ps_pwrite(struct ps_prochandle *P, psaddr_t addr, const void *buf, size_t size)
  67   69  {
  68   70          if (P->ops.pop_pwrite(P, buf, size, addr, P->data) != size)
  69   71                  return (PS_BADADDR);
  70   72          return (PS_OK);
  71   73  }
  72   74  
  73   75  /*
  74   76   * libc_db calls matched pairs of ps_pstop()/ps_pcontinue()
  75   77   * in the belief that the client may have left the process
  76   78   * running while calling in to the libc_db interfaces.
  77   79   *
  78   80   * We interpret the meaning of these functions to be an inquiry
  79   81   * as to whether the process is stopped, not an action to be
  80   82   * performed to make it stopped.  For similar reasons, we also
  81   83   * return PS_OK for core files in order to allow libc_db to
  82   84   * operate on these as well.
  83   85   */
  84   86  ps_err_e
  85   87  ps_pstop(struct ps_prochandle *P)
  86   88  {
  87   89          if (P->state != PS_STOP && P->state != PS_DEAD)
  88   90                  return (PS_ERR);
  89   91          return (PS_OK);
  90   92  }
  91   93  
  92   94  ps_err_e
  93   95  ps_pcontinue(struct ps_prochandle *P)
  94   96  {
  95   97          if (P->state != PS_STOP && P->state != PS_DEAD)
  96   98                  return (PS_ERR);
  97   99          return (PS_OK);
  98  100  }
  99  101  
 100  102  /*
 101  103   * ps_lstop() and ps_lcontinue() are not called by any code in libc_db
 102  104   * or librtld_db.  We make them behave like ps_pstop() and ps_pcontinue().
 103  105   */
 104  106  /* ARGSUSED1 */
 105  107  ps_err_e
 106  108  ps_lstop(struct ps_prochandle *P, lwpid_t lwpid)
 107  109  {
 108  110          if (P->state != PS_STOP && P->state != PS_DEAD)
 109  111                  return (PS_ERR);
 110  112          return (PS_OK);
 111  113  }
 112  114  
 113  115  /* ARGSUSED1 */
 114  116  ps_err_e
 115  117  ps_lcontinue(struct ps_prochandle *P, lwpid_t lwpid)
 116  118  {
 117  119          if (P->state != PS_STOP && P->state != PS_DEAD)
 118  120                  return (PS_ERR);
 119  121          return (PS_OK);
 120  122  }
 121  123  
 122  124  ps_err_e
 123  125  ps_lgetregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t regs)
 124  126  {
 125  127          if (P->state != PS_STOP && P->state != PS_DEAD)
 126  128                  return (PS_ERR);
 127  129  
 128  130          if (Plwp_getregs(P, lwpid, regs) == 0)
 129  131                  return (PS_OK);
 130  132  
 131  133          return (PS_BADLID);
 132  134  }
 133  135  
 134  136  ps_err_e
 135  137  ps_lsetregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t regs)
 136  138  {
 137  139          if (P->state != PS_STOP)
 138  140                  return (PS_ERR);
 139  141  
 140  142          if (Plwp_setregs(P, lwpid, regs) == 0)
 141  143                  return (PS_OK);
 142  144  
 143  145          return (PS_BADLID);
 144  146  }
 145  147  
 146  148  ps_err_e
 147  149  ps_lgetfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *regs)
 148  150  {
 149  151          if (P->state != PS_STOP && P->state != PS_DEAD)
 150  152                  return (PS_ERR);
 151  153  
 152  154          if (Plwp_getfpregs(P, lwpid, regs) == 0)
 153  155                  return (PS_OK);
 154  156  
 155  157          return (PS_BADLID);
 156  158  }
 157  159  
 158  160  ps_err_e
 159  161  ps_lsetfpregs(struct ps_prochandle *P, lwpid_t lwpid, const prfpregset_t *regs)
  
    | 
      ↓ open down ↓ | 
    119 lines elided | 
    
      ↑ open up ↑ | 
  
 160  162  {
 161  163          if (P->state != PS_STOP)
 162  164                  return (PS_ERR);
 163  165  
 164  166          if (Plwp_setfpregs(P, lwpid, regs) == 0)
 165  167                  return (PS_OK);
 166  168  
 167  169          return (PS_BADLID);
 168  170  }
 169  171  
 170      -#if defined(sparc) || defined(__sparc)
 171      -
 172  172  ps_err_e
 173  173  ps_lgetxregsize(struct ps_prochandle *P, lwpid_t lwpid, int *xrsize)
 174  174  {
 175  175          char fname[PATH_MAX];
 176  176          struct stat statb;
 177  177  
 178  178          if (P->state == PS_DEAD) {
 179  179                  core_info_t *core = P->data;
 180  180                  lwp_info_t *lwp;
 181  181  
 182  182                  for (lwp = list_head(&core->core_lwp_head); lwp != NULL;
 183  183                      lwp = list_next(&core->core_lwp_head, lwp)) {
 184  184                          if (lwp->lwp_id == lwpid) {
 185      -                                if (lwp->lwp_xregs != NULL)
 186      -                                        *xrsize = sizeof (prxregset_t);
 187      -                                else
      185 +                                if (lwp->lwp_xregs != NULL &&
      186 +                                    lwp->lwp_xregsize > 0) {
      187 +                                        if (lwp->lwp_xregsize >= INT_MAX) {
      188 +                                                return (PS_ERR);
      189 +                                        }
      190 +
      191 +                                        *xrsize = (int)lwp->lwp_xregsize;
      192 +                                } else {
 188  193                                          *xrsize = 0;
      194 +                                }
 189  195                                  return (PS_OK);
 190  196                          }
 191  197                  }
 192  198  
 193  199                  return (PS_BADLID);
 194  200          }
 195  201  
 196  202          (void) snprintf(fname, sizeof (fname), "%s/%d/lwp/%d/xregs",
 197  203              procfs_path, (int)P->status.pr_pid, (int)lwpid);
 198  204  
 199  205          if (stat(fname, &statb) != 0)
 200  206                  return (PS_BADLID);
 201  207  
      208 +        if (statb.st_size > INT_MAX)
      209 +                return (PS_ERR);
      210 +
 202  211          *xrsize = (int)statb.st_size;
 203  212          return (PS_OK);
 204  213  }
 205  214  
 206  215  ps_err_e
 207  216  ps_lgetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
 208  217  {
      218 +        size_t xregsize;
      219 +        prxregset_t *prx;
      220 +
 209  221          if (P->state != PS_STOP && P->state != PS_DEAD)
 210  222                  return (PS_ERR);
 211  223  
 212      -        /* LINTED - alignment */
 213      -        if (Plwp_getxregs(P, lwpid, (prxregset_t *)xregs) == 0)
      224 +        if (Plwp_getxregs(P, lwpid, &prx, &xregsize) == 0) {
      225 +                (void) memcpy(xregs, prx, xregsize);
      226 +                Plwp_freexregs(P, prx, xregsize);
 214  227                  return (PS_OK);
      228 +        }
 215  229  
      230 +        if (errno == ENODATA)
      231 +                return (PS_NOXREGS);
      232 +
 216  233          return (PS_BADLID);
 217  234  }
 218  235  
 219  236  ps_err_e
 220  237  ps_lsetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
      238 +{
      239 +        size_t xregsize = 0;
      240 +
      241 +        if (P->state != PS_STOP)
      242 +                return (PS_ERR);
      243 +
      244 +        /*
      245 +         * libproc asks the caller for the size of the extended register set.
      246 +         * Unfortunately, right now we aren't given the actual size of this
      247 +         * ourselves and we don't want to break the ABI that folks have used
      248 +         * historically. Therefore, we reach in and ask the structure in a
      249 +         * platform-specific way about what this should be. Sorry, this is a bit
      250 +         * unfortunate. This really shouldn't be a platform-specific #ifdef.
      251 +         */
      252 +#if defined(__i386) || defined(__amd64)
      253 +        prxregset_hdr_t *hdr = (prxregset_hdr_t *)xregs;
      254 +        xregsize = hdr->pr_size;
      255 +#endif
      256 +        if (xregsize == 0)
      257 +                return (PS_ERR);
      258 +
      259 +        if (Plwp_setxregs(P, lwpid, (prxregset_t *)xregs, xregsize) == 0)
      260 +                return (PS_OK);
      261 +
      262 +        return (PS_BADLID);
      263 +}
      264 +
      265 +#if defined(sparc) || defined(__sparc)
      266 +ps_err_e
      267 +ps_lsetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
 221  268  {
 222  269          if (P->state != PS_STOP)
 223  270                  return (PS_ERR);
 224  271  
 225  272          /* LINTED - alignment */
 226  273          if (Plwp_setxregs(P, lwpid, (prxregset_t *)xregs) == 0)
 227  274                  return (PS_OK);
 228  275  
 229  276          return (PS_BADLID);
 230  277  }
 231  278  
 232  279  #endif  /* sparc */
 233  280  
 234  281  #if defined(__i386) || defined(__amd64)
 235  282  
 236  283  ps_err_e
 237  284  ps_lgetLDT(struct ps_prochandle *P, lwpid_t lwpid, struct ssd *ldt)
 238  285  {
 239  286  #if defined(__amd64) && defined(_LP64)
 240  287          if (P->status.pr_dmodel != PR_MODEL_NATIVE) {
 241  288  #endif
 242  289          prgregset_t regs;
 243  290          struct ssd *ldtarray;
 244  291          ps_err_e error;
 245  292          uint_t gs;
 246  293          int nldt;
 247  294          int i;
 248  295  
 249  296          if (P->state != PS_STOP && P->state != PS_DEAD)
 250  297                  return (PS_ERR);
 251  298  
 252  299          /*
 253  300           * We need to get the ldt entry that matches the
 254  301           * value in the lwp's GS register.
 255  302           */
 256  303          if ((error = ps_lgetregs(P, lwpid, regs)) != PS_OK)
 257  304                  return (error);
 258  305  
 259  306          gs = regs[GS];
 260  307  
 261  308          if ((nldt = Pldt(P, NULL, 0)) <= 0 ||
 262  309              (ldtarray = malloc(nldt * sizeof (struct ssd))) == NULL)
 263  310                  return (PS_ERR);
 264  311          if ((nldt = Pldt(P, ldtarray, nldt)) <= 0) {
 265  312                  free(ldtarray);
 266  313                  return (PS_ERR);
 267  314          }
 268  315  
 269  316          for (i = 0; i < nldt; i++) {
 270  317                  if (gs == ldtarray[i].sel) {
 271  318                          *ldt = ldtarray[i];
 272  319                          break;
 273  320                  }
 274  321          }
 275  322          free(ldtarray);
 276  323  
 277  324          if (i < nldt)
 278  325                  return (PS_OK);
 279  326  #if defined(__amd64) && defined(_LP64)
 280  327          }
 281  328  #endif
 282  329  
 283  330          return (PS_ERR);
 284  331  }
 285  332  
 286  333  #endif  /* __i386 || __amd64 */
 287  334  
 288  335  /*
 289  336   * Libthread_db doesn't use this function currently, but librtld_db uses
 290  337   * it for its debugging output.  We turn this on via rd_log if our debugging
 291  338   * switch is on, and then echo the messages sent to ps_plog to stderr.
 292  339   */
 293  340  void
 294  341  ps_plog(const char *fmt, ...)
 295  342  {
 296  343          va_list ap;
 297  344  
 298  345          if (_libproc_debug && fmt != NULL && *fmt != '\0') {
 299  346                  va_start(ap, fmt);
 300  347                  (void) vfprintf(stderr, fmt, ap);
 301  348                  va_end(ap);
 302  349                  if (fmt[strlen(fmt) - 1] != '\n')
 303  350                          (void) fputc('\n', stderr);
 304  351          }
 305  352  }
 306  353  
 307  354  /*
 308  355   * Store a pointer to our internal copy of the aux vector at the address
 309  356   * specified by the caller.  It should not hold on to this data for too long.
 310  357   */
 311  358  ps_err_e
 312  359  ps_pauxv(struct ps_prochandle *P, const auxv_t **aux)
 313  360  {
 314  361          if (P->auxv == NULL)
 315  362                  Preadauxvec(P);
 316  363  
 317  364          if (P->auxv == NULL)
 318  365                  return (PS_ERR);
 319  366  
 320  367          *aux = (const auxv_t *)P->auxv;
 321  368          return (PS_OK);
 322  369  }
 323  370  
 324  371  ps_err_e
 325  372  ps_pbrandname(struct ps_prochandle *P, char *buf, size_t len)
 326  373  {
 327  374          return (Pbrandname(P, buf, len) ? PS_OK : PS_ERR);
 328  375  }
 329  376  
 330  377  /*
 331  378   * Search for a symbol by name and return the corresponding address.
 332  379   */
 333  380  ps_err_e
 334  381  ps_pglobal_lookup(struct ps_prochandle *P, const char *object_name,
 335  382      const char *sym_name, psaddr_t *sym_addr)
 336  383  {
 337  384          GElf_Sym sym;
 338  385  
 339  386          if (Plookup_by_name(P, object_name, sym_name, &sym) == 0) {
 340  387                  dprintf("pglobal_lookup <%s> -> %p\n",
 341  388                      sym_name, (void *)(uintptr_t)sym.st_value);
 342  389                  *sym_addr = (psaddr_t)sym.st_value;
 343  390                  return (PS_OK);
 344  391          }
 345  392  
 346  393          return (PS_NOSYM);
 347  394  }
 348  395  
 349  396  /*
 350  397   * Search for a symbol by name and return the corresponding symbol
 351  398   * information.  If we're compiled _LP64, we just call Plookup_by_name
 352  399   * and return because ps_sym_t is defined to be an Elf64_Sym, which
 353  400   * is the same as a GElf_Sym.  In the _ILP32 case, we have to convert
 354  401   * Plookup_by_name's result back to a ps_sym_t (which is an Elf32_Sym).
 355  402   */
 356  403  ps_err_e
 357  404  ps_pglobal_sym(struct ps_prochandle *P, const char *object_name,
 358  405      const char *sym_name, ps_sym_t *symp)
 359  406  {
 360  407  #if defined(_ILP32)
 361  408          GElf_Sym sym;
 362  409  
 363  410          if (Plookup_by_name(P, object_name, sym_name, &sym) == 0) {
 364  411                  symp->st_name = (Elf32_Word)sym.st_name;
 365  412                  symp->st_value = (Elf32_Addr)sym.st_value;
 366  413                  symp->st_size = (Elf32_Word)sym.st_size;
 367  414                  symp->st_info = ELF32_ST_INFO(
 368  415                      GELF_ST_BIND(sym.st_info), GELF_ST_TYPE(sym.st_info));
 369  416                  symp->st_other = sym.st_other;
 370  417                  symp->st_shndx = sym.st_shndx;
 371  418                  return (PS_OK);
 372  419          }
 373  420  
 374  421  #elif defined(_LP64)
 375  422          if (Plookup_by_name(P, object_name, sym_name, symp) == 0)
 376  423                  return (PS_OK);
 377  424  #endif
 378  425          return (PS_NOSYM);
 379  426  }
  
    | 
      ↓ open down ↓ | 
    149 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX