Print this page
    
11927 Log, or optionally panic, on zero-length kmem allocations
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Jason King <jason.brian.king@gmail.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/mdb/common/modules/genunix/genunix.c
          +++ new/usr/src/cmd/mdb/common/modules/genunix/genunix.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
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  23   23   * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2019 Joyent, Inc.
  25   25   * Copyright (c) 2013 by Delphix. All rights reserved.
  26   26   */
  27   27  
  28   28  #include <mdb/mdb_param.h>
  29   29  #include <mdb/mdb_modapi.h>
  30   30  #include <mdb/mdb_ks.h>
  31   31  #include <mdb/mdb_ctf.h>
  32   32  
  33   33  #include <sys/types.h>
  34   34  #include <sys/thread.h>
  35   35  #include <sys/session.h>
  36   36  #include <sys/user.h>
  37   37  #include <sys/proc.h>
  38   38  #include <sys/var.h>
  39   39  #include <sys/t_lock.h>
  40   40  #include <sys/callo.h>
  41   41  #include <sys/priocntl.h>
  42   42  #include <sys/class.h>
  43   43  #include <sys/regset.h>
  44   44  #include <sys/stack.h>
  45   45  #include <sys/cpuvar.h>
  46   46  #include <sys/vnode.h>
  47   47  #include <sys/vfs.h>
  48   48  #include <sys/flock_impl.h>
  49   49  #include <sys/kmem_impl.h>
  50   50  #include <sys/vmem_impl.h>
  51   51  #include <sys/kstat.h>
  52   52  #include <sys/dditypes.h>
  53   53  #include <sys/ddi_impldefs.h>
  54   54  #include <sys/sysmacros.h>
  55   55  #include <sys/sysconf.h>
  56   56  #include <sys/task.h>
  57   57  #include <sys/project.h>
  58   58  #include <sys/errorq_impl.h>
  59   59  #include <sys/cred_impl.h>
  60   60  #include <sys/zone.h>
  61   61  #include <sys/panic.h>
  62   62  #include <regex.h>
  63   63  #include <sys/port_impl.h>
  64   64  #include <sys/contract/process_impl.h>
  65   65  
  66   66  #include "avl.h"
  67   67  #include "bio.h"
  68   68  #include "bitset.h"
  69   69  #include "combined.h"
  70   70  #include "contract.h"
  71   71  #include "cpupart_mdb.h"
  72   72  #include "cred.h"
  73   73  #include "ctxop.h"
  74   74  #include "cyclic.h"
  75   75  #include "damap.h"
  76   76  #include "ddi_periodic.h"
  77   77  #include "devinfo.h"
  78   78  #include "dnlc.h"
  79   79  #include "findstack.h"
  80   80  #include "fm.h"
  81   81  #include "gcore.h"
  82   82  #include "group.h"
  83   83  #include "irm.h"
  84   84  #include "kgrep.h"
  85   85  #include "kmem.h"
  86   86  #include "ldi.h"
  87   87  #include "leaky.h"
  88   88  #include "lgrp.h"
  89   89  #include "list.h"
  90   90  #include "log.h"
  91   91  #include "mdi.h"
  92   92  #include "memory.h"
  93   93  #include "mmd.h"
  94   94  #include "modhash.h"
  95   95  #include "ndievents.h"
  96   96  #include "net.h"
  97   97  #include "netstack.h"
  98   98  #include "nvpair.h"
  99   99  #include "pci.h"
 100  100  #include "pg.h"
 101  101  #include "rctl.h"
 102  102  #include "sobj.h"
 103  103  #include "streams.h"
 104  104  #include "sysevent.h"
 105  105  #include "taskq.h"
 106  106  #include "thread.h"
 107  107  #include "tsd.h"
 108  108  #include "tsol.h"
 109  109  #include "typegraph.h"
 110  110  #include "vfs.h"
 111  111  #include "zone.h"
 112  112  #include "hotplug.h"
 113  113  
 114  114  /*
 115  115   * Surely this is defined somewhere...
 116  116   */
 117  117  #define NINTR           16
 118  118  
 119  119  #define KILOS           10
 120  120  #define MEGS            20
 121  121  #define GIGS            30
 122  122  
 123  123  #ifndef STACK_BIAS
 124  124  #define STACK_BIAS      0
 125  125  #endif
 126  126  
 127  127  static char
 128  128  pstat2ch(uchar_t state)
 129  129  {
 130  130          switch (state) {
 131  131                  case SSLEEP: return ('S');
 132  132                  case SRUN: return ('R');
 133  133                  case SZOMB: return ('Z');
 134  134                  case SIDL: return ('I');
 135  135                  case SONPROC: return ('O');
 136  136                  case SSTOP: return ('T');
 137  137                  case SWAIT: return ('W');
 138  138                  default: return ('?');
 139  139          }
 140  140  }
 141  141  
 142  142  #define PS_PRTTHREADS   0x1
 143  143  #define PS_PRTLWPS      0x2
 144  144  #define PS_PSARGS       0x4
 145  145  #define PS_TASKS        0x8
 146  146  #define PS_PROJECTS     0x10
 147  147  #define PS_ZONES        0x20
 148  148  #define PS_SERVICES     0x40
 149  149  
 150  150  static int
 151  151  ps_threadprint(uintptr_t addr, const void *data, void *private)
 152  152  {
 153  153          const kthread_t *t = (const kthread_t *)data;
 154  154          uint_t prt_flags = *((uint_t *)private);
 155  155  
 156  156          static const mdb_bitmask_t t_state_bits[] = {
 157  157                  { "TS_FREE",    UINT_MAX,       TS_FREE         },
 158  158                  { "TS_SLEEP",   TS_SLEEP,       TS_SLEEP        },
 159  159                  { "TS_RUN",     TS_RUN,         TS_RUN          },
 160  160                  { "TS_ONPROC",  TS_ONPROC,      TS_ONPROC       },
 161  161                  { "TS_ZOMB",    TS_ZOMB,        TS_ZOMB         },
 162  162                  { "TS_STOPPED", TS_STOPPED,     TS_STOPPED      },
 163  163                  { "TS_WAIT",    TS_WAIT,        TS_WAIT         },
 164  164                  { NULL,         0,              0               }
 165  165          };
 166  166  
 167  167          if (prt_flags & PS_PRTTHREADS)
 168  168                  mdb_printf("\tT  %?a <%b>\n", addr, t->t_state, t_state_bits);
 169  169  
 170  170          if (prt_flags & PS_PRTLWPS) {
 171  171                  char desc[128] = "";
 172  172  
 173  173                  (void) thread_getdesc(addr, B_FALSE, desc, sizeof (desc));
 174  174  
 175  175                  mdb_printf("\tL  %?a ID: %s\n", t->t_lwp, desc);
 176  176          }
 177  177  
 178  178          return (WALK_NEXT);
 179  179  }
 180  180  
 181  181  typedef struct mdb_pflags_proc {
 182  182          struct pid      *p_pidp;
 183  183          ushort_t        p_pidflag;
 184  184          uint_t          p_proc_flag;
 185  185          uint_t          p_flag;
 186  186  } mdb_pflags_proc_t;
 187  187  
 188  188  static int
 189  189  pflags(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 190  190  {
 191  191          mdb_pflags_proc_t pr;
 192  192          struct pid pid;
 193  193  
 194  194          static const mdb_bitmask_t p_flag_bits[] = {
 195  195                  { "SSYS",               SSYS,           SSYS            },
 196  196                  { "SEXITING",           SEXITING,       SEXITING        },
 197  197                  { "SITBUSY",            SITBUSY,        SITBUSY         },
 198  198                  { "SFORKING",           SFORKING,       SFORKING        },
 199  199                  { "SWATCHOK",           SWATCHOK,       SWATCHOK        },
 200  200                  { "SKILLED",            SKILLED,        SKILLED         },
 201  201                  { "SSCONT",             SSCONT,         SSCONT          },
 202  202                  { "SZONETOP",           SZONETOP,       SZONETOP        },
 203  203                  { "SEXTKILLED",         SEXTKILLED,     SEXTKILLED      },
 204  204                  { "SUGID",              SUGID,          SUGID           },
 205  205                  { "SEXECED",            SEXECED,        SEXECED         },
 206  206                  { "SJCTL",              SJCTL,          SJCTL           },
 207  207                  { "SNOWAIT",            SNOWAIT,        SNOWAIT         },
 208  208                  { "SVFORK",             SVFORK,         SVFORK          },
 209  209                  { "SVFWAIT",            SVFWAIT,        SVFWAIT         },
 210  210                  { "SEXITLWPS",          SEXITLWPS,      SEXITLWPS       },
 211  211                  { "SHOLDFORK",          SHOLDFORK,      SHOLDFORK       },
 212  212                  { "SHOLDFORK1",         SHOLDFORK1,     SHOLDFORK1      },
 213  213                  { "SCOREDUMP",          SCOREDUMP,      SCOREDUMP       },
 214  214                  { "SMSACCT",            SMSACCT,        SMSACCT         },
 215  215                  { "SLWPWRAP",           SLWPWRAP,       SLWPWRAP        },
 216  216                  { "SAUTOLPG",           SAUTOLPG,       SAUTOLPG        },
 217  217                  { "SNOCD",              SNOCD,          SNOCD           },
 218  218                  { "SHOLDWATCH",         SHOLDWATCH,     SHOLDWATCH      },
 219  219                  { "SMSFORK",            SMSFORK,        SMSFORK         },
 220  220                  { "SDOCORE",            SDOCORE,        SDOCORE         },
 221  221                  { NULL,                 0,              0               }
 222  222          };
 223  223  
 224  224          static const mdb_bitmask_t p_pidflag_bits[] = {
 225  225                  { "CLDPEND",            CLDPEND,        CLDPEND         },
 226  226                  { "CLDCONT",            CLDCONT,        CLDCONT         },
 227  227                  { "CLDNOSIGCHLD",       CLDNOSIGCHLD,   CLDNOSIGCHLD    },
 228  228                  { "CLDWAITPID",         CLDWAITPID,     CLDWAITPID      },
 229  229                  { NULL,                 0,              0               }
 230  230          };
 231  231  
 232  232          static const mdb_bitmask_t p_proc_flag_bits[] = {
 233  233                  { "P_PR_TRACE",         P_PR_TRACE,     P_PR_TRACE      },
 234  234                  { "P_PR_PTRACE",        P_PR_PTRACE,    P_PR_PTRACE     },
 235  235                  { "P_PR_FORK",          P_PR_FORK,      P_PR_FORK       },
 236  236                  { "P_PR_LOCK",          P_PR_LOCK,      P_PR_LOCK       },
 237  237                  { "P_PR_ASYNC",         P_PR_ASYNC,     P_PR_ASYNC      },
 238  238                  { "P_PR_EXEC",          P_PR_EXEC,      P_PR_EXEC       },
 239  239                  { "P_PR_BPTADJ",        P_PR_BPTADJ,    P_PR_BPTADJ     },
 240  240                  { "P_PR_RUNLCL",        P_PR_RUNLCL,    P_PR_RUNLCL     },
 241  241                  { "P_PR_KILLCL",        P_PR_KILLCL,    P_PR_KILLCL     },
 242  242                  { NULL,                 0,              0               }
 243  243          };
 244  244  
 245  245          if (!(flags & DCMD_ADDRSPEC)) {
 246  246                  if (mdb_walk_dcmd("proc", "pflags", argc, argv) == -1) {
 247  247                          mdb_warn("can't walk 'proc'");
 248  248                          return (DCMD_ERR);
 249  249                  }
 250  250                  return (DCMD_OK);
 251  251          }
 252  252  
 253  253          if (mdb_ctf_vread(&pr, "proc_t", "mdb_pflags_proc_t", addr, 0) == -1 ||
 254  254              mdb_vread(&pid, sizeof (pid), (uintptr_t)pr.p_pidp) == -1) {
 255  255                  mdb_warn("cannot read proc_t or pid");
 256  256                  return (DCMD_ERR);
 257  257          }
 258  258  
 259  259          mdb_printf("%p [pid %d]:\n", addr, pid.pid_id);
 260  260          mdb_printf("\tp_flag:      %08x <%b>\n", pr.p_flag, pr.p_flag,
 261  261              p_flag_bits);
 262  262          mdb_printf("\tp_pidflag:   %08x <%b>\n", pr.p_pidflag, pr.p_pidflag,
 263  263              p_pidflag_bits);
 264  264          mdb_printf("\tp_proc_flag: %08x <%b>\n", pr.p_proc_flag, pr.p_proc_flag,
 265  265              p_proc_flag_bits);
 266  266  
 267  267          return (DCMD_OK);
 268  268  }
 269  269  
 270  270  typedef struct mdb_ps_proc {
 271  271          char            p_stat;
 272  272          struct pid      *p_pidp;
 273  273          struct pid      *p_pgidp;
 274  274          struct cred     *p_cred;
 275  275          struct sess     *p_sessp;
 276  276          struct task     *p_task;
 277  277          struct zone     *p_zone;
 278  278          struct cont_process *p_ct_process;
 279  279          pid_t           p_ppid;
 280  280          uint_t          p_flag;
 281  281          struct {
 282  282                  char            u_comm[MAXCOMLEN + 1];
 283  283                  char            u_psargs[PSARGSZ];
 284  284          } p_user;
 285  285  } mdb_ps_proc_t;
 286  286  
 287  287  /*
 288  288   * A reasonable enough limit. Note that we purposefully let this column over-run
 289  289   * if needed.
 290  290   */
 291  291  #define FMRI_LEN (128)
 292  292  
 293  293  int
 294  294  ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 295  295  {
 296  296          uint_t prt_flags = 0;
 297  297          mdb_ps_proc_t pr;
 298  298          struct pid pid, pgid, sid;
 299  299          sess_t session;
 300  300          cred_t cred;
 301  301          task_t tk;
 302  302          kproject_t pj;
 303  303          zone_t zn;
 304  304          struct cont_process cp;
 305  305          char fmri[FMRI_LEN] = "";
 306  306  
 307  307          if (!(flags & DCMD_ADDRSPEC)) {
 308  308                  if (mdb_walk_dcmd("proc", "ps", argc, argv) == -1) {
 309  309                          mdb_warn("can't walk 'proc'");
 310  310                          return (DCMD_ERR);
 311  311                  }
 312  312                  return (DCMD_OK);
 313  313          }
 314  314  
 315  315          if (mdb_getopts(argc, argv,
 316  316              'f', MDB_OPT_SETBITS, PS_PSARGS, &prt_flags,
 317  317              'l', MDB_OPT_SETBITS, PS_PRTLWPS, &prt_flags,
 318  318              's', MDB_OPT_SETBITS, PS_SERVICES, &prt_flags,
 319  319              'T', MDB_OPT_SETBITS, PS_TASKS, &prt_flags,
 320  320              'P', MDB_OPT_SETBITS, PS_PROJECTS, &prt_flags,
 321  321              'z', MDB_OPT_SETBITS, PS_ZONES, &prt_flags,
 322  322              't', MDB_OPT_SETBITS, PS_PRTTHREADS, &prt_flags, NULL) != argc)
 323  323                  return (DCMD_USAGE);
 324  324  
 325  325          if (DCMD_HDRSPEC(flags)) {
 326  326                  mdb_printf("%<u>%-1s %-6s %-6s %-6s %-6s ",
 327  327                      "S", "PID", "PPID", "PGID", "SID");
 328  328                  if (prt_flags & PS_TASKS)
 329  329                          mdb_printf("%-5s ", "TASK");
 330  330                  if (prt_flags & PS_PROJECTS)
 331  331                          mdb_printf("%-5s ", "PROJ");
 332  332                  if (prt_flags & PS_ZONES)
 333  333                          mdb_printf("%-5s ", "ZONE");
 334  334                  if (prt_flags & PS_SERVICES)
 335  335                          mdb_printf("%-40s ", "SERVICE");
 336  336                  mdb_printf("%-6s %-10s %-?s %-s%</u>\n",
 337  337                      "UID", "FLAGS", "ADDR", "NAME");
 338  338          }
 339  339  
 340  340          if (mdb_ctf_vread(&pr, "proc_t", "mdb_ps_proc_t", addr, 0) == -1)
 341  341                  return (DCMD_ERR);
 342  342  
 343  343          mdb_vread(&pid, sizeof (pid), (uintptr_t)pr.p_pidp);
 344  344          mdb_vread(&pgid, sizeof (pgid), (uintptr_t)pr.p_pgidp);
 345  345          mdb_vread(&cred, sizeof (cred), (uintptr_t)pr.p_cred);
 346  346          mdb_vread(&session, sizeof (session), (uintptr_t)pr.p_sessp);
 347  347          mdb_vread(&sid, sizeof (sid), (uintptr_t)session.s_sidp);
 348  348          if (prt_flags & (PS_TASKS | PS_PROJECTS))
 349  349                  mdb_vread(&tk, sizeof (tk), (uintptr_t)pr.p_task);
 350  350          if (prt_flags & PS_PROJECTS)
 351  351                  mdb_vread(&pj, sizeof (pj), (uintptr_t)tk.tk_proj);
 352  352          if (prt_flags & PS_ZONES)
 353  353                  mdb_vread(&zn, sizeof (zn), (uintptr_t)pr.p_zone);
 354  354          if ((prt_flags & PS_SERVICES) && pr.p_ct_process != NULL) {
 355  355                  mdb_vread(&cp, sizeof (cp), (uintptr_t)pr.p_ct_process);
 356  356  
 357  357                  if (mdb_read_refstr((uintptr_t)cp.conp_svc_fmri, fmri,
 358  358                      sizeof (fmri)) <= 0)
 359  359                          (void) strlcpy(fmri, "?", sizeof (fmri));
 360  360  
 361  361                  /* Strip any standard prefix and suffix. */
 362  362                  if (strncmp(fmri, "svc:/", sizeof ("svc:/") - 1) == 0) {
 363  363                          char *i = fmri;
 364  364                          char *j = fmri + sizeof ("svc:/") - 1;
 365  365                          for (; *j != '\0'; i++, j++) {
 366  366                                  if (strcmp(j, ":default") == 0)
 367  367                                          break;
 368  368                                  *i = *j;
 369  369                          }
 370  370  
 371  371                          *i = '\0';
 372  372                  }
 373  373          }
 374  374  
 375  375          mdb_printf("%-c %-6d %-6d %-6d %-6d ",
 376  376              pstat2ch(pr.p_stat), pid.pid_id, pr.p_ppid, pgid.pid_id,
 377  377              sid.pid_id);
 378  378          if (prt_flags & PS_TASKS)
 379  379                  mdb_printf("%-5d ", tk.tk_tkid);
 380  380          if (prt_flags & PS_PROJECTS)
 381  381                  mdb_printf("%-5d ", pj.kpj_id);
 382  382          if (prt_flags & PS_ZONES)
 383  383                  mdb_printf("%-5d ", zn.zone_id);
 384  384          if (prt_flags & PS_SERVICES)
 385  385                  mdb_printf("%-40s ", fmri);
 386  386          mdb_printf("%-6d 0x%08x %0?p %-s\n",
 387  387              cred.cr_uid, pr.p_flag, addr,
 388  388              (prt_flags & PS_PSARGS) ? pr.p_user.u_psargs : pr.p_user.u_comm);
 389  389  
 390  390          if (prt_flags & ~PS_PSARGS)
 391  391                  (void) mdb_pwalk("thread", ps_threadprint, &prt_flags, addr);
 392  392  
 393  393          return (DCMD_OK);
 394  394  }
 395  395  
 396  396  static void
 397  397  ps_help(void)
 398  398  {
 399  399          mdb_printf("Display processes.\n\n"
 400  400              "Options:\n"
 401  401              "    -f\tDisplay command arguments\n"
 402  402              "    -l\tDisplay LWPs\n"
 403  403              "    -T\tDisplay tasks\n"
 404  404              "    -P\tDisplay projects\n"
 405  405              "    -s\tDisplay SMF FMRI\n"
 406  406              "    -z\tDisplay zones\n"
 407  407              "    -t\tDisplay threads\n\n");
 408  408  
 409  409          mdb_printf("The resulting output is a table of the processes on the "
 410  410              "system.  The\n"
 411  411              "columns in the output consist of a combination of the "
 412  412              "following fields:\n\n");
 413  413          mdb_printf("S\tProcess state.  Possible states are:\n"
 414  414              "\tS\tSleeping (SSLEEP)\n"
 415  415              "\tR\tRunnable (SRUN)\n"
 416  416              "\tZ\tZombie (SZOMB)\n"
 417  417              "\tI\tIdle (SIDL)\n"
 418  418              "\tO\tOn Cpu (SONPROC)\n"
 419  419              "\tT\tStopped (SSTOP)\n"
 420  420              "\tW\tWaiting (SWAIT)\n");
 421  421  
 422  422          mdb_printf("PID\tProcess id.\n");
 423  423          mdb_printf("PPID\tParent process id.\n");
 424  424          mdb_printf("PGID\tProcess group id.\n");
 425  425          mdb_printf("SID\tProcess id of the session leader.\n");
 426  426          mdb_printf("TASK\tThe task id of the process.\n");
 427  427          mdb_printf("PROJ\tThe project id of the process.\n");
 428  428          mdb_printf("ZONE\tThe zone id of the process.\n");
 429  429          mdb_printf("SERVICE The SMF service FMRI of the process.\n");
 430  430          mdb_printf("UID\tThe user id of the process.\n");
 431  431          mdb_printf("FLAGS\tThe process flags (see ::pflags).\n");
 432  432          mdb_printf("ADDR\tThe kernel address of the proc_t structure of the "
 433  433              "process\n");
 434  434          mdb_printf("NAME\tThe name (p_user.u_comm field) of the process.  If "
 435  435              "the -f flag\n"
 436  436              "\tis specified, the arguments of the process are displayed.\n");
 437  437  }
 438  438  
 439  439  #define PG_NEWEST       0x0001
 440  440  #define PG_OLDEST       0x0002
 441  441  #define PG_PIPE_OUT     0x0004
 442  442  #define PG_EXACT_MATCH  0x0008
 443  443  
 444  444  typedef struct pgrep_data {
 445  445          uint_t pg_flags;
 446  446          uint_t pg_psflags;
 447  447          uintptr_t pg_xaddr;
 448  448          hrtime_t pg_xstart;
 449  449          const char *pg_pat;
 450  450  #ifndef _KMDB
 451  451          regex_t pg_reg;
 452  452  #endif
 453  453  } pgrep_data_t;
 454  454  
 455  455  typedef struct mdb_pgrep_proc {
 456  456          struct {
 457  457                  timestruc_t     u_start;
 458  458                  char            u_comm[MAXCOMLEN + 1];
 459  459          } p_user;
 460  460  } mdb_pgrep_proc_t;
 461  461  
 462  462  /*ARGSUSED*/
 463  463  static int
 464  464  pgrep_cb(uintptr_t addr, const void *ignored, void *data)
 465  465  {
 466  466          mdb_pgrep_proc_t p;
 467  467          pgrep_data_t *pgp = data;
 468  468  #ifndef _KMDB
 469  469          regmatch_t pmatch;
 470  470  #endif
 471  471  
 472  472          if (mdb_ctf_vread(&p, "proc_t", "mdb_pgrep_proc_t", addr, 0) == -1)
 473  473                  return (WALK_ERR);
 474  474  
 475  475          /*
 476  476           * kmdb doesn't have access to the reg* functions, so we fall back
 477  477           * to strstr/strcmp.
 478  478           */
 479  479  #ifdef _KMDB
 480  480          if ((pgp->pg_flags & PG_EXACT_MATCH) ?
 481  481              (strcmp(p.p_user.u_comm, pgp->pg_pat) != 0) :
 482  482              (strstr(p.p_user.u_comm, pgp->pg_pat) == NULL))
 483  483                  return (WALK_NEXT);
 484  484  #else
 485  485          if (regexec(&pgp->pg_reg, p.p_user.u_comm, 1, &pmatch, 0) != 0)
 486  486                  return (WALK_NEXT);
 487  487  
 488  488          if ((pgp->pg_flags & PG_EXACT_MATCH) &&
 489  489              (pmatch.rm_so != 0 || p.p_user.u_comm[pmatch.rm_eo] != '\0'))
 490  490                  return (WALK_NEXT);
 491  491  #endif
 492  492  
 493  493          if (pgp->pg_flags & (PG_NEWEST | PG_OLDEST)) {
 494  494                  hrtime_t start;
 495  495  
 496  496                  start = (hrtime_t)p.p_user.u_start.tv_sec * NANOSEC +
 497  497                      p.p_user.u_start.tv_nsec;
 498  498  
 499  499                  if (pgp->pg_flags & PG_NEWEST) {
 500  500                          if (pgp->pg_xaddr == 0 || start > pgp->pg_xstart) {
 501  501                                  pgp->pg_xaddr = addr;
 502  502                                  pgp->pg_xstart = start;
 503  503                          }
 504  504                  } else {
 505  505                          if (pgp->pg_xaddr == 0 || start < pgp->pg_xstart) {
 506  506                                  pgp->pg_xaddr = addr;
 507  507                                  pgp->pg_xstart = start;
 508  508                          }
 509  509                  }
 510  510  
 511  511          } else if (pgp->pg_flags & PG_PIPE_OUT) {
 512  512                  mdb_printf("%p\n", addr);
 513  513  
 514  514          } else {
 515  515                  if (mdb_call_dcmd("ps", addr, pgp->pg_psflags, 0, NULL) != 0) {
 516  516                          mdb_warn("can't invoke 'ps'");
 517  517                          return (WALK_DONE);
 518  518                  }
 519  519                  pgp->pg_psflags &= ~DCMD_LOOPFIRST;
 520  520          }
 521  521  
 522  522          return (WALK_NEXT);
 523  523  }
 524  524  
 525  525  /*ARGSUSED*/
 526  526  int
 527  527  pgrep(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 528  528  {
 529  529          pgrep_data_t pg;
 530  530          int i;
 531  531  #ifndef _KMDB
 532  532          int err;
 533  533  #endif
 534  534  
 535  535          if (flags & DCMD_ADDRSPEC)
 536  536                  return (DCMD_USAGE);
 537  537  
 538  538          pg.pg_flags = 0;
 539  539          pg.pg_xaddr = 0;
 540  540  
 541  541          i = mdb_getopts(argc, argv,
 542  542              'n', MDB_OPT_SETBITS, PG_NEWEST, &pg.pg_flags,
 543  543              'o', MDB_OPT_SETBITS, PG_OLDEST, &pg.pg_flags,
 544  544              'x', MDB_OPT_SETBITS, PG_EXACT_MATCH, &pg.pg_flags,
 545  545              NULL);
 546  546  
 547  547          argc -= i;
 548  548          argv += i;
 549  549  
 550  550          if (argc != 1)
 551  551                  return (DCMD_USAGE);
 552  552  
 553  553          /*
 554  554           * -n and -o are mutually exclusive.
 555  555           */
 556  556          if ((pg.pg_flags & PG_NEWEST) && (pg.pg_flags & PG_OLDEST))
 557  557                  return (DCMD_USAGE);
 558  558  
 559  559          if (argv->a_type != MDB_TYPE_STRING)
 560  560                  return (DCMD_USAGE);
 561  561  
 562  562          if (flags & DCMD_PIPE_OUT)
 563  563                  pg.pg_flags |= PG_PIPE_OUT;
 564  564  
 565  565          pg.pg_pat = argv->a_un.a_str;
 566  566          if (DCMD_HDRSPEC(flags))
 567  567                  pg.pg_psflags = DCMD_ADDRSPEC | DCMD_LOOP | DCMD_LOOPFIRST;
 568  568          else
 569  569                  pg.pg_psflags = DCMD_ADDRSPEC | DCMD_LOOP;
 570  570  
 571  571  #ifndef _KMDB
 572  572          if ((err = regcomp(&pg.pg_reg, pg.pg_pat, REG_EXTENDED)) != 0) {
 573  573                  size_t nbytes;
 574  574                  char *buf;
 575  575  
 576  576                  nbytes = regerror(err, &pg.pg_reg, NULL, 0);
 577  577                  buf = mdb_alloc(nbytes + 1, UM_SLEEP | UM_GC);
 578  578                  (void) regerror(err, &pg.pg_reg, buf, nbytes);
 579  579                  mdb_warn("%s\n", buf);
 580  580  
 581  581                  return (DCMD_ERR);
 582  582          }
 583  583  #endif
 584  584  
 585  585          if (mdb_walk("proc", pgrep_cb, &pg) != 0) {
 586  586                  mdb_warn("can't walk 'proc'");
 587  587                  return (DCMD_ERR);
 588  588          }
 589  589  
 590  590          if (pg.pg_xaddr != 0 && (pg.pg_flags & (PG_NEWEST | PG_OLDEST))) {
 591  591                  if (pg.pg_flags & PG_PIPE_OUT) {
 592  592                          mdb_printf("%p\n", pg.pg_xaddr);
 593  593                  } else {
 594  594                          if (mdb_call_dcmd("ps", pg.pg_xaddr, pg.pg_psflags,
 595  595                              0, NULL) != 0) {
 596  596                                  mdb_warn("can't invoke 'ps'");
 597  597                                  return (DCMD_ERR);
 598  598                          }
 599  599                  }
 600  600          }
 601  601  
 602  602          return (DCMD_OK);
 603  603  }
 604  604  
 605  605  int
 606  606  task(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 607  607  {
 608  608          task_t tk;
 609  609          kproject_t pj;
 610  610  
 611  611          if (!(flags & DCMD_ADDRSPEC)) {
 612  612                  if (mdb_walk_dcmd("task_cache", "task", argc, argv) == -1) {
 613  613                          mdb_warn("can't walk task_cache");
 614  614                          return (DCMD_ERR);
 615  615                  }
 616  616                  return (DCMD_OK);
 617  617          }
 618  618          if (DCMD_HDRSPEC(flags)) {
 619  619                  mdb_printf("%<u>%?s %6s %6s %6s %6s %10s%</u>\n",
 620  620                      "ADDR", "TASKID", "PROJID", "ZONEID", "REFCNT", "FLAGS");
 621  621          }
 622  622          if (mdb_vread(&tk, sizeof (task_t), addr) == -1) {
 623  623                  mdb_warn("can't read task_t structure at %p", addr);
 624  624                  return (DCMD_ERR);
 625  625          }
 626  626          if (mdb_vread(&pj, sizeof (kproject_t), (uintptr_t)tk.tk_proj) == -1) {
 627  627                  mdb_warn("can't read project_t structure at %p", addr);
 628  628                  return (DCMD_ERR);
 629  629          }
 630  630          mdb_printf("%0?p %6d %6d %6d %6u 0x%08x\n",
 631  631              addr, tk.tk_tkid, pj.kpj_id, pj.kpj_zoneid, tk.tk_hold_count,
 632  632              tk.tk_flags);
 633  633          return (DCMD_OK);
 634  634  }
 635  635  
 636  636  int
 637  637  project(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 638  638  {
 639  639          kproject_t pj;
 640  640  
 641  641          if (!(flags & DCMD_ADDRSPEC)) {
 642  642                  if (mdb_walk_dcmd("projects", "project", argc, argv) == -1) {
 643  643                          mdb_warn("can't walk projects");
 644  644                          return (DCMD_ERR);
 645  645                  }
 646  646                  return (DCMD_OK);
 647  647          }
 648  648          if (DCMD_HDRSPEC(flags)) {
 649  649                  mdb_printf("%<u>%?s %6s %6s %6s%</u>\n",
 650  650                      "ADDR", "PROJID", "ZONEID", "REFCNT");
 651  651          }
 652  652          if (mdb_vread(&pj, sizeof (kproject_t), addr) == -1) {
 653  653                  mdb_warn("can't read kproject_t structure at %p", addr);
 654  654                  return (DCMD_ERR);
 655  655          }
 656  656          mdb_printf("%0?p %6d %6d %6u\n", addr, pj.kpj_id, pj.kpj_zoneid,
 657  657              pj.kpj_count);
 658  658          return (DCMD_OK);
 659  659  }
 660  660  
 661  661  /* walk callouts themselves, either by list or id hash. */
 662  662  int
 663  663  callout_walk_init(mdb_walk_state_t *wsp)
 664  664  {
 665  665          if (wsp->walk_addr == 0) {
 666  666                  mdb_warn("callout doesn't support global walk");
 667  667                  return (WALK_ERR);
 668  668          }
 669  669          wsp->walk_data = mdb_alloc(sizeof (callout_t), UM_SLEEP);
 670  670          return (WALK_NEXT);
 671  671  }
 672  672  
 673  673  #define CALLOUT_WALK_BYLIST     0
 674  674  #define CALLOUT_WALK_BYID       1
 675  675  
 676  676  /* the walker arg switches between walking by list (0) and walking by id (1). */
 677  677  int
 678  678  callout_walk_step(mdb_walk_state_t *wsp)
 679  679  {
 680  680          int retval;
 681  681  
 682  682          if (wsp->walk_addr == 0) {
 683  683                  return (WALK_DONE);
 684  684          }
 685  685          if (mdb_vread(wsp->walk_data, sizeof (callout_t),
 686  686              wsp->walk_addr) == -1) {
 687  687                  mdb_warn("failed to read callout at %p", wsp->walk_addr);
 688  688                  return (WALK_DONE);
 689  689          }
 690  690          retval = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
 691  691              wsp->walk_cbdata);
 692  692  
 693  693          if ((ulong_t)wsp->walk_arg == CALLOUT_WALK_BYID) {
 694  694                  wsp->walk_addr =
 695  695                      (uintptr_t)(((callout_t *)wsp->walk_data)->c_idnext);
 696  696          } else {
 697  697                  wsp->walk_addr =
 698  698                      (uintptr_t)(((callout_t *)wsp->walk_data)->c_clnext);
 699  699          }
 700  700  
 701  701          return (retval);
 702  702  }
 703  703  
 704  704  void
 705  705  callout_walk_fini(mdb_walk_state_t *wsp)
 706  706  {
 707  707          mdb_free(wsp->walk_data, sizeof (callout_t));
 708  708  }
 709  709  
 710  710  /*
 711  711   * walker for callout lists. This is different from hashes and callouts.
 712  712   * Thankfully, it's also simpler.
 713  713   */
 714  714  int
 715  715  callout_list_walk_init(mdb_walk_state_t *wsp)
 716  716  {
 717  717          if (wsp->walk_addr == 0) {
 718  718                  mdb_warn("callout list doesn't support global walk");
 719  719                  return (WALK_ERR);
 720  720          }
 721  721          wsp->walk_data = mdb_alloc(sizeof (callout_list_t), UM_SLEEP);
 722  722          return (WALK_NEXT);
 723  723  }
 724  724  
 725  725  int
 726  726  callout_list_walk_step(mdb_walk_state_t *wsp)
 727  727  {
 728  728          int retval;
 729  729  
 730  730          if (wsp->walk_addr == 0) {
 731  731                  return (WALK_DONE);
 732  732          }
 733  733          if (mdb_vread(wsp->walk_data, sizeof (callout_list_t),
 734  734              wsp->walk_addr) != sizeof (callout_list_t)) {
 735  735                  mdb_warn("failed to read callout_list at %p", wsp->walk_addr);
 736  736                  return (WALK_ERR);
 737  737          }
 738  738          retval = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
 739  739              wsp->walk_cbdata);
 740  740  
 741  741          wsp->walk_addr = (uintptr_t)
 742  742              (((callout_list_t *)wsp->walk_data)->cl_next);
 743  743  
 744  744          return (retval);
 745  745  }
 746  746  
 747  747  void
 748  748  callout_list_walk_fini(mdb_walk_state_t *wsp)
 749  749  {
 750  750          mdb_free(wsp->walk_data, sizeof (callout_list_t));
 751  751  }
 752  752  
 753  753  /* routines/structs to walk callout table(s) */
 754  754  typedef struct cot_data {
 755  755          callout_table_t *ct0;
 756  756          callout_table_t ct;
 757  757          callout_hash_t cot_idhash[CALLOUT_BUCKETS];
 758  758          callout_hash_t cot_clhash[CALLOUT_BUCKETS];
 759  759          kstat_named_t ct_kstat_data[CALLOUT_NUM_STATS];
 760  760          int cotndx;
 761  761          int cotsize;
 762  762  } cot_data_t;
 763  763  
 764  764  int
 765  765  callout_table_walk_init(mdb_walk_state_t *wsp)
 766  766  {
 767  767          int max_ncpus;
 768  768          cot_data_t *cot_walk_data;
 769  769  
 770  770          cot_walk_data = mdb_alloc(sizeof (cot_data_t), UM_SLEEP);
 771  771  
 772  772          if (wsp->walk_addr == 0) {
 773  773                  if (mdb_readvar(&cot_walk_data->ct0, "callout_table") == -1) {
 774  774                          mdb_warn("failed to read 'callout_table'");
 775  775                          return (WALK_ERR);
 776  776                  }
 777  777                  if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) {
 778  778                          mdb_warn("failed to get callout_table array size");
 779  779                          return (WALK_ERR);
 780  780                  }
 781  781                  cot_walk_data->cotsize = CALLOUT_NTYPES * max_ncpus;
 782  782                  wsp->walk_addr = (uintptr_t)cot_walk_data->ct0;
 783  783          } else {
 784  784                  /* not a global walk */
 785  785                  cot_walk_data->cotsize = 1;
 786  786          }
 787  787  
 788  788          cot_walk_data->cotndx = 0;
 789  789          wsp->walk_data = cot_walk_data;
 790  790  
 791  791          return (WALK_NEXT);
 792  792  }
 793  793  
 794  794  int
 795  795  callout_table_walk_step(mdb_walk_state_t *wsp)
 796  796  {
 797  797          int retval;
 798  798          cot_data_t *cotwd = (cot_data_t *)wsp->walk_data;
 799  799          size_t size;
 800  800  
 801  801          if (cotwd->cotndx >= cotwd->cotsize) {
 802  802                  return (WALK_DONE);
 803  803          }
 804  804          if (mdb_vread(&(cotwd->ct), sizeof (callout_table_t),
 805  805              wsp->walk_addr) != sizeof (callout_table_t)) {
 806  806                  mdb_warn("failed to read callout_table at %p", wsp->walk_addr);
 807  807                  return (WALK_ERR);
 808  808          }
 809  809  
 810  810          size = sizeof (callout_hash_t) * CALLOUT_BUCKETS;
 811  811          if (cotwd->ct.ct_idhash != NULL) {
 812  812                  if (mdb_vread(cotwd->cot_idhash, size,
 813  813                      (uintptr_t)(cotwd->ct.ct_idhash)) != size) {
 814  814                          mdb_warn("failed to read id_hash at %p",
 815  815                              cotwd->ct.ct_idhash);
 816  816                          return (WALK_ERR);
 817  817                  }
 818  818          }
 819  819          if (cotwd->ct.ct_clhash != NULL) {
 820  820                  if (mdb_vread(&(cotwd->cot_clhash), size,
 821  821                      (uintptr_t)cotwd->ct.ct_clhash) == -1) {
 822  822                          mdb_warn("failed to read cl_hash at %p",
 823  823                              cotwd->ct.ct_clhash);
 824  824                          return (WALK_ERR);
 825  825                  }
 826  826          }
 827  827          size = sizeof (kstat_named_t) * CALLOUT_NUM_STATS;
 828  828          if (cotwd->ct.ct_kstat_data != NULL) {
 829  829                  if (mdb_vread(&(cotwd->ct_kstat_data), size,
 830  830                      (uintptr_t)cotwd->ct.ct_kstat_data) == -1) {
 831  831                          mdb_warn("failed to read kstats at %p",
 832  832                              cotwd->ct.ct_kstat_data);
 833  833                          return (WALK_ERR);
 834  834                  }
 835  835          }
 836  836          retval = wsp->walk_callback(wsp->walk_addr, (void *)cotwd,
 837  837              wsp->walk_cbdata);
 838  838  
 839  839          cotwd->cotndx++;
 840  840          if (cotwd->cotndx >= cotwd->cotsize) {
 841  841                  return (WALK_DONE);
 842  842          }
 843  843          wsp->walk_addr = (uintptr_t)((char *)wsp->walk_addr +
 844  844              sizeof (callout_table_t));
 845  845  
 846  846          return (retval);
 847  847  }
 848  848  
 849  849  void
 850  850  callout_table_walk_fini(mdb_walk_state_t *wsp)
 851  851  {
 852  852          mdb_free(wsp->walk_data, sizeof (cot_data_t));
 853  853  }
 854  854  
 855  855  static const char *co_typenames[] = { "R", "N" };
 856  856  
 857  857  #define CO_PLAIN_ID(xid)        ((xid) & CALLOUT_ID_MASK)
 858  858  
 859  859  #define TABLE_TO_SEQID(x)       ((x) >> CALLOUT_TYPE_BITS)
 860  860  
 861  861  /* callout flags, in no particular order */
 862  862  #define COF_REAL        0x00000001
 863  863  #define COF_NORM        0x00000002
 864  864  #define COF_LONG        0x00000004
 865  865  #define COF_SHORT       0x00000008
 866  866  #define COF_EMPTY       0x00000010
 867  867  #define COF_TIME        0x00000020
 868  868  #define COF_BEFORE      0x00000040
 869  869  #define COF_AFTER       0x00000080
 870  870  #define COF_SEQID       0x00000100
 871  871  #define COF_FUNC        0x00000200
 872  872  #define COF_ADDR        0x00000400
 873  873  #define COF_EXEC        0x00000800
 874  874  #define COF_HIRES       0x00001000
 875  875  #define COF_ABS         0x00002000
 876  876  #define COF_TABLE       0x00004000
 877  877  #define COF_BYIDH       0x00008000
 878  878  #define COF_FREE        0x00010000
 879  879  #define COF_LIST        0x00020000
 880  880  #define COF_EXPREL      0x00040000
 881  881  #define COF_HDR         0x00080000
 882  882  #define COF_VERBOSE     0x00100000
 883  883  #define COF_LONGLIST    0x00200000
 884  884  #define COF_THDR        0x00400000
 885  885  #define COF_LHDR        0x00800000
 886  886  #define COF_CHDR        0x01000000
 887  887  #define COF_PARAM       0x02000000
 888  888  #define COF_DECODE      0x04000000
 889  889  #define COF_HEAP        0x08000000
 890  890  #define COF_QUEUE       0x10000000
 891  891  
 892  892  /* show real and normal, short and long, expired and unexpired. */
 893  893  #define COF_DEFAULT     (COF_REAL | COF_NORM | COF_LONG | COF_SHORT)
 894  894  
 895  895  #define COF_LIST_FLAGS  \
 896  896          (CALLOUT_LIST_FLAG_HRESTIME | CALLOUT_LIST_FLAG_ABSOLUTE)
 897  897  
 898  898  /* private callout data for callback functions */
 899  899  typedef struct callout_data {
 900  900          uint_t flags;           /* COF_* */
 901  901          cpu_t *cpu;             /* cpu pointer if given */
 902  902          int seqid;              /* cpu seqid, or -1 */
 903  903          hrtime_t time;          /* expiration time value */
 904  904          hrtime_t atime;         /* expiration before value */
 905  905          hrtime_t btime;         /* expiration after value */
 906  906          uintptr_t funcaddr;     /* function address or NULL */
 907  907          uintptr_t param;        /* parameter to function or NULL */
 908  908          hrtime_t now;           /* current system time */
 909  909          int nsec_per_tick;      /* for conversions */
 910  910          ulong_t ctbits;         /* for decoding xid */
 911  911          callout_table_t *co_table;      /* top of callout table array */
 912  912          int ndx;                /* table index. */
 913  913          int bucket;             /* which list/id bucket are we in */
 914  914          hrtime_t exp;           /* expire time */
 915  915          int list_flags;         /* copy of cl_flags */
 916  916  } callout_data_t;
 917  917  
 918  918  /* this callback does the actual callback itself (finally). */
 919  919  /*ARGSUSED*/
 920  920  static int
 921  921  callouts_cb(uintptr_t addr, const void *data, void *priv)
 922  922  {
 923  923          callout_data_t *coargs = (callout_data_t *)priv;
 924  924          callout_t *co = (callout_t *)data;
 925  925          int tableid, list_flags;
 926  926          callout_id_t coid;
 927  927  
 928  928          if ((coargs == NULL) || (co == NULL)) {
 929  929                  return (WALK_ERR);
 930  930          }
 931  931  
 932  932          if ((coargs->flags & COF_FREE) && !(co->c_xid & CALLOUT_ID_FREE)) {
 933  933                  /*
 934  934                   * The callout must have been reallocated. No point in
 935  935                   * walking any more.
 936  936                   */
 937  937                  return (WALK_DONE);
 938  938          }
 939  939          if (!(coargs->flags & COF_FREE) && (co->c_xid & CALLOUT_ID_FREE)) {
 940  940                  /*
 941  941                   * The callout must have been freed. No point in
 942  942                   * walking any more.
 943  943                   */
 944  944                  return (WALK_DONE);
 945  945          }
 946  946          if ((coargs->flags & COF_FUNC) &&
 947  947              (coargs->funcaddr != (uintptr_t)co->c_func)) {
 948  948                  return (WALK_NEXT);
 949  949          }
 950  950          if ((coargs->flags & COF_PARAM) &&
 951  951              (coargs->param != (uintptr_t)co->c_arg)) {
 952  952                  return (WALK_NEXT);
 953  953          }
 954  954          if (!(coargs->flags & COF_LONG) && (co->c_xid & CALLOUT_LONGTERM)) {
 955  955                  return (WALK_NEXT);
 956  956          }
 957  957          if (!(coargs->flags & COF_SHORT) && !(co->c_xid & CALLOUT_LONGTERM)) {
 958  958                  return (WALK_NEXT);
 959  959          }
 960  960          if ((coargs->flags & COF_EXEC) && !(co->c_xid & CALLOUT_EXECUTING)) {
 961  961                  return (WALK_NEXT);
 962  962          }
 963  963          /* it is possible we don't have the exp time or flags */
 964  964          if (coargs->flags & COF_BYIDH) {
 965  965                  if (!(coargs->flags & COF_FREE)) {
 966  966                          /* we have to fetch the expire time ourselves. */
 967  967                          if (mdb_vread(&coargs->exp, sizeof (hrtime_t),
 968  968                              (uintptr_t)co->c_list + offsetof(callout_list_t,
 969  969                              cl_expiration)) == -1) {
 970  970                                  mdb_warn("failed to read expiration "
 971  971                                      "time from %p", co->c_list);
 972  972                                  coargs->exp = 0;
 973  973                          }
 974  974                          /* and flags. */
 975  975                          if (mdb_vread(&coargs->list_flags, sizeof (int),
 976  976                              (uintptr_t)co->c_list + offsetof(callout_list_t,
 977  977                              cl_flags)) == -1) {
 978  978                                  mdb_warn("failed to read list flags"
 979  979                                      "from %p", co->c_list);
 980  980                                  coargs->list_flags = 0;
 981  981                          }
 982  982                  } else {
 983  983                          /* free callouts can't use list pointer. */
 984  984                          coargs->exp = 0;
 985  985                          coargs->list_flags = 0;
 986  986                  }
 987  987                  if (coargs->exp != 0) {
 988  988                          if ((coargs->flags & COF_TIME) &&
 989  989                              (coargs->exp != coargs->time)) {
 990  990                                  return (WALK_NEXT);
 991  991                          }
 992  992                          if ((coargs->flags & COF_BEFORE) &&
 993  993                              (coargs->exp > coargs->btime)) {
 994  994                                  return (WALK_NEXT);
 995  995                          }
 996  996                          if ((coargs->flags & COF_AFTER) &&
 997  997                              (coargs->exp < coargs->atime)) {
 998  998                                  return (WALK_NEXT);
 999  999                          }
1000 1000                  }
1001 1001                  /* tricky part, since both HIRES and ABS can be set */
1002 1002                  list_flags = coargs->list_flags;
1003 1003                  if ((coargs->flags & COF_HIRES) && (coargs->flags & COF_ABS)) {
1004 1004                          /* both flags are set, only skip "regular" ones */
1005 1005                          if (! (list_flags & COF_LIST_FLAGS)) {
1006 1006                                  return (WALK_NEXT);
1007 1007                          }
1008 1008                  } else {
1009 1009                          /* individual flags, or no flags */
1010 1010                          if ((coargs->flags & COF_HIRES) &&
1011 1011                              !(list_flags & CALLOUT_LIST_FLAG_HRESTIME)) {
1012 1012                                  return (WALK_NEXT);
1013 1013                          }
1014 1014                          if ((coargs->flags & COF_ABS) &&
1015 1015                              !(list_flags & CALLOUT_LIST_FLAG_ABSOLUTE)) {
1016 1016                                  return (WALK_NEXT);
1017 1017                          }
1018 1018                  }
1019 1019                  /*
1020 1020                   * We do the checks for COF_HEAP and COF_QUEUE here only if we
1021 1021                   * are traversing BYIDH. If the traversal is by callout list,
1022 1022                   * we do this check in callout_list_cb() to be more
1023 1023                   * efficient.
1024 1024                   */
1025 1025                  if ((coargs->flags & COF_HEAP) &&
1026 1026                      !(list_flags & CALLOUT_LIST_FLAG_HEAPED)) {
1027 1027                          return (WALK_NEXT);
1028 1028                  }
1029 1029  
1030 1030                  if ((coargs->flags & COF_QUEUE) &&
1031 1031                      !(list_flags & CALLOUT_LIST_FLAG_QUEUED)) {
1032 1032                          return (WALK_NEXT);
1033 1033                  }
1034 1034          }
1035 1035  
1036 1036  #define callout_table_mask      ((1 << coargs->ctbits) - 1)
1037 1037          tableid = CALLOUT_ID_TO_TABLE(co->c_xid);
1038 1038  #undef  callout_table_mask
1039 1039          coid = CO_PLAIN_ID(co->c_xid);
1040 1040  
1041 1041          if ((coargs->flags & COF_CHDR) && !(coargs->flags & COF_ADDR)) {
1042 1042                  /*
1043 1043                   * We need to print the headers. If walking by id, then
1044 1044                   * the list header isn't printed, so we must include
1045 1045                   * that info here.
1046 1046                   */
1047 1047                  if (!(coargs->flags & COF_VERBOSE)) {
1048 1048                          mdb_printf("%<u>%3s %-1s %-14s %</u>",
1049 1049                              "SEQ", "T", "EXP");
1050 1050                  } else if (coargs->flags & COF_BYIDH) {
1051 1051                          mdb_printf("%<u>%-14s %</u>", "EXP");
1052 1052                  }
1053 1053                  mdb_printf("%<u>%-4s %-?s %-20s%</u>",
1054 1054                      "XHAL", "XID", "FUNC(ARG)");
1055 1055                  if (coargs->flags & COF_LONGLIST) {
1056 1056                          mdb_printf("%<u> %-?s %-?s %-?s %-?s%</u>",
1057 1057                              "PREVID", "NEXTID", "PREVL", "NEXTL");
1058 1058                          mdb_printf("%<u> %-?s %-4s %-?s%</u>",
1059 1059                              "DONE", "UTOS", "THREAD");
1060 1060                  }
1061 1061                  mdb_printf("\n");
1062 1062                  coargs->flags &= ~COF_CHDR;
1063 1063                  coargs->flags |= (COF_THDR | COF_LHDR);
1064 1064          }
1065 1065  
1066 1066          if (!(coargs->flags & COF_ADDR)) {
1067 1067                  if (!(coargs->flags & COF_VERBOSE)) {
1068 1068                          mdb_printf("%-3d %1s %-14llx ",
1069 1069                              TABLE_TO_SEQID(tableid),
1070 1070                              co_typenames[tableid & CALLOUT_TYPE_MASK],
1071 1071                              (coargs->flags & COF_EXPREL) ?
1072 1072                              coargs->exp - coargs->now : coargs->exp);
1073 1073                  } else if (coargs->flags & COF_BYIDH) {
1074 1074                          mdb_printf("%-14x ",
1075 1075                              (coargs->flags & COF_EXPREL) ?
1076 1076                              coargs->exp - coargs->now : coargs->exp);
1077 1077                  }
1078 1078                  list_flags = coargs->list_flags;
1079 1079                  mdb_printf("%1s%1s%1s%1s %-?llx %a(%p)",
1080 1080                      (co->c_xid & CALLOUT_EXECUTING) ? "X" : " ",
1081 1081                      (list_flags & CALLOUT_LIST_FLAG_HRESTIME) ? "H" : " ",
1082 1082                      (list_flags & CALLOUT_LIST_FLAG_ABSOLUTE) ? "A" : " ",
1083 1083                      (co->c_xid & CALLOUT_LONGTERM) ? "L" : " ",
1084 1084                      (long long)coid, co->c_func, co->c_arg);
1085 1085                  if (coargs->flags & COF_LONGLIST) {
1086 1086                          mdb_printf(" %-?p %-?p %-?p %-?p",
1087 1087                              co->c_idprev, co->c_idnext, co->c_clprev,
1088 1088                              co->c_clnext);
1089 1089                          mdb_printf(" %-?p %-4d %-0?p",
1090 1090                              co->c_done, co->c_waiting, co->c_executor);
1091 1091                  }
1092 1092          } else {
1093 1093                  /* address only */
1094 1094                  mdb_printf("%-0p", addr);
1095 1095          }
1096 1096          mdb_printf("\n");
1097 1097          return (WALK_NEXT);
1098 1098  }
1099 1099  
1100 1100  /* this callback is for callout list handling. idhash is done by callout_t_cb */
1101 1101  /*ARGSUSED*/
1102 1102  static int
1103 1103  callout_list_cb(uintptr_t addr, const void *data, void *priv)
1104 1104  {
1105 1105          callout_data_t *coargs = (callout_data_t *)priv;
1106 1106          callout_list_t *cl = (callout_list_t *)data;
1107 1107          callout_t *coptr;
1108 1108          int list_flags;
1109 1109  
1110 1110          if ((coargs == NULL) || (cl == NULL)) {
1111 1111                  return (WALK_ERR);
1112 1112          }
1113 1113  
1114 1114          coargs->exp = cl->cl_expiration;
1115 1115          coargs->list_flags = cl->cl_flags;
1116 1116          if ((coargs->flags & COF_FREE) &&
1117 1117              !(cl->cl_flags & CALLOUT_LIST_FLAG_FREE)) {
1118 1118                  /*
1119 1119                   * The callout list must have been reallocated. No point in
1120 1120                   * walking any more.
1121 1121                   */
1122 1122                  return (WALK_DONE);
1123 1123          }
1124 1124          if (!(coargs->flags & COF_FREE) &&
1125 1125              (cl->cl_flags & CALLOUT_LIST_FLAG_FREE)) {
1126 1126                  /*
1127 1127                   * The callout list must have been freed. No point in
1128 1128                   * walking any more.
1129 1129                   */
1130 1130                  return (WALK_DONE);
1131 1131          }
1132 1132          if ((coargs->flags & COF_TIME) &&
1133 1133              (cl->cl_expiration != coargs->time)) {
1134 1134                  return (WALK_NEXT);
1135 1135          }
1136 1136          if ((coargs->flags & COF_BEFORE) &&
1137 1137              (cl->cl_expiration > coargs->btime)) {
1138 1138                  return (WALK_NEXT);
1139 1139          }
1140 1140          if ((coargs->flags & COF_AFTER) &&
1141 1141              (cl->cl_expiration < coargs->atime)) {
1142 1142                  return (WALK_NEXT);
1143 1143          }
1144 1144          if (!(coargs->flags & COF_EMPTY) &&
1145 1145              (cl->cl_callouts.ch_head == NULL)) {
1146 1146                  return (WALK_NEXT);
1147 1147          }
1148 1148          /* FOUR cases, each different, !A!B, !AB, A!B, AB */
1149 1149          if ((coargs->flags & COF_HIRES) && (coargs->flags & COF_ABS)) {
1150 1150                  /* both flags are set, only skip "regular" ones */
1151 1151                  if (! (cl->cl_flags & COF_LIST_FLAGS)) {
1152 1152                          return (WALK_NEXT);
1153 1153                  }
1154 1154          } else {
1155 1155                  if ((coargs->flags & COF_HIRES) &&
1156 1156                      !(cl->cl_flags & CALLOUT_LIST_FLAG_HRESTIME)) {
1157 1157                          return (WALK_NEXT);
1158 1158                  }
1159 1159                  if ((coargs->flags & COF_ABS) &&
1160 1160                      !(cl->cl_flags & CALLOUT_LIST_FLAG_ABSOLUTE)) {
1161 1161                          return (WALK_NEXT);
1162 1162                  }
1163 1163          }
1164 1164  
1165 1165          if ((coargs->flags & COF_HEAP) &&
1166 1166              !(coargs->list_flags & CALLOUT_LIST_FLAG_HEAPED)) {
1167 1167                  return (WALK_NEXT);
1168 1168          }
1169 1169  
1170 1170          if ((coargs->flags & COF_QUEUE) &&
1171 1171              !(coargs->list_flags & CALLOUT_LIST_FLAG_QUEUED)) {
1172 1172                  return (WALK_NEXT);
1173 1173          }
1174 1174  
1175 1175          if ((coargs->flags & COF_LHDR) && !(coargs->flags & COF_ADDR) &&
1176 1176              (coargs->flags & (COF_LIST | COF_VERBOSE))) {
1177 1177                  if (!(coargs->flags & COF_VERBOSE)) {
1178 1178                          /* don't be redundant again */
1179 1179                          mdb_printf("%<u>SEQ T %</u>");
1180 1180                  }
1181 1181                  mdb_printf("%<u>EXP            HA BUCKET "
1182 1182                      "CALLOUTS         %</u>");
1183 1183  
1184 1184                  if (coargs->flags & COF_LONGLIST) {
1185 1185                          mdb_printf("%<u> %-?s %-?s%</u>",
1186 1186                              "PREV", "NEXT");
1187 1187                  }
1188 1188                  mdb_printf("\n");
1189 1189                  coargs->flags &= ~COF_LHDR;
1190 1190                  coargs->flags |= (COF_THDR | COF_CHDR);
1191 1191          }
1192 1192          if (coargs->flags & (COF_LIST | COF_VERBOSE)) {
1193 1193                  if (!(coargs->flags & COF_ADDR)) {
1194 1194                          if (!(coargs->flags & COF_VERBOSE)) {
1195 1195                                  mdb_printf("%3d %1s ",
1196 1196                                      TABLE_TO_SEQID(coargs->ndx),
1197 1197                                      co_typenames[coargs->ndx &
1198 1198                                      CALLOUT_TYPE_MASK]);
1199 1199                          }
1200 1200  
1201 1201                          list_flags = coargs->list_flags;
1202 1202                          mdb_printf("%-14llx %1s%1s %-6d %-0?p ",
1203 1203                              (coargs->flags & COF_EXPREL) ?
1204 1204                              coargs->exp - coargs->now : coargs->exp,
1205 1205                              (list_flags & CALLOUT_LIST_FLAG_HRESTIME) ?
1206 1206                              "H" : " ",
1207 1207                              (list_flags & CALLOUT_LIST_FLAG_ABSOLUTE) ?
1208 1208                              "A" : " ",
1209 1209                              coargs->bucket, cl->cl_callouts.ch_head);
1210 1210  
1211 1211                          if (coargs->flags & COF_LONGLIST) {
1212 1212                                  mdb_printf(" %-?p %-?p",
1213 1213                                      cl->cl_prev, cl->cl_next);
1214 1214                          }
1215 1215                  } else {
1216 1216                          /* address only */
1217 1217                          mdb_printf("%-0p", addr);
1218 1218                  }
1219 1219                  mdb_printf("\n");
1220 1220                  if (coargs->flags & COF_LIST) {
1221 1221                          return (WALK_NEXT);
1222 1222                  }
1223 1223          }
1224 1224          /* yet another layer as we walk the actual callouts via list. */
1225 1225          if (cl->cl_callouts.ch_head == NULL) {
1226 1226                  return (WALK_NEXT);
1227 1227          }
1228 1228          /* free list structures do not have valid callouts off of them. */
1229 1229          if (coargs->flags & COF_FREE) {
1230 1230                  return (WALK_NEXT);
1231 1231          }
1232 1232          coptr = (callout_t *)cl->cl_callouts.ch_head;
1233 1233  
1234 1234          if (coargs->flags & COF_VERBOSE) {
1235 1235                  mdb_inc_indent(4);
1236 1236          }
1237 1237          /*
1238 1238           * walk callouts using yet another callback routine.
1239 1239           * we use callouts_bytime because id hash is handled via
1240 1240           * the callout_t_cb callback.
1241 1241           */
1242 1242          if (mdb_pwalk("callouts_bytime", callouts_cb, coargs,
1243 1243              (uintptr_t)coptr) == -1) {
1244 1244                  mdb_warn("cannot walk callouts at %p", coptr);
1245 1245                  return (WALK_ERR);
1246 1246          }
1247 1247          if (coargs->flags & COF_VERBOSE) {
1248 1248                  mdb_dec_indent(4);
1249 1249          }
1250 1250  
1251 1251          return (WALK_NEXT);
1252 1252  }
1253 1253  
1254 1254  /* this callback handles the details of callout table walking. */
1255 1255  static int
1256 1256  callout_t_cb(uintptr_t addr, const void *data, void *priv)
1257 1257  {
1258 1258          callout_data_t *coargs = (callout_data_t *)priv;
1259 1259          cot_data_t *cotwd = (cot_data_t *)data;
1260 1260          callout_table_t *ct = &(cotwd->ct);
1261 1261          int index, seqid, cotype;
1262 1262          int i;
1263 1263          callout_list_t *clptr;
1264 1264          callout_t *coptr;
1265 1265  
1266 1266          if ((coargs == NULL) || (ct == NULL) || (coargs->co_table == NULL)) {
1267 1267                  return (WALK_ERR);
1268 1268          }
1269 1269  
1270 1270          index =  ((char *)addr - (char *)coargs->co_table) /
1271 1271              sizeof (callout_table_t);
1272 1272          cotype = index & CALLOUT_TYPE_MASK;
1273 1273          seqid = TABLE_TO_SEQID(index);
1274 1274  
1275 1275          if ((coargs->flags & COF_SEQID) && (coargs->seqid != seqid)) {
1276 1276                  return (WALK_NEXT);
1277 1277          }
1278 1278  
1279 1279          if (!(coargs->flags & COF_REAL) && (cotype == CALLOUT_REALTIME)) {
1280 1280                  return (WALK_NEXT);
1281 1281          }
1282 1282  
1283 1283          if (!(coargs->flags & COF_NORM) && (cotype == CALLOUT_NORMAL)) {
1284 1284                  return (WALK_NEXT);
1285 1285          }
1286 1286  
1287 1287          if (!(coargs->flags & COF_EMPTY) && (
1288 1288              (ct->ct_heap == NULL) || (ct->ct_cyclic == 0))) {
1289 1289                  return (WALK_NEXT);
1290 1290          }
1291 1291  
1292 1292          if ((coargs->flags & COF_THDR) && !(coargs->flags & COF_ADDR) &&
1293 1293              (coargs->flags & (COF_TABLE | COF_VERBOSE))) {
1294 1294                  /* print table hdr */
1295 1295                  mdb_printf("%<u>%-3s %-1s %-?s %-?s %-?s %-?s%</u>",
1296 1296                      "SEQ", "T", "FREE", "LFREE", "CYCLIC", "HEAP");
1297 1297                  coargs->flags &= ~COF_THDR;
1298 1298                  coargs->flags |= (COF_LHDR | COF_CHDR);
1299 1299                  if (coargs->flags & COF_LONGLIST) {
1300 1300                          /* more info! */
1301 1301                          mdb_printf("%<u> %-T%-7s %-7s %-?s %-?s %-?s"
1302 1302                              " %-?s %-?s %-?s%</u>",
1303 1303                              "HEAPNUM", "HEAPMAX", "TASKQ", "EXPQ", "QUE",
1304 1304                              "PEND", "FREE", "LOCK");
1305 1305                  }
1306 1306                  mdb_printf("\n");
1307 1307          }
1308 1308          if (coargs->flags & (COF_TABLE | COF_VERBOSE)) {
1309 1309                  if (!(coargs->flags & COF_ADDR)) {
1310 1310                          mdb_printf("%-3d %-1s %-0?p %-0?p %-0?p %-?p",
1311 1311                              seqid, co_typenames[cotype],
1312 1312                              ct->ct_free, ct->ct_lfree, ct->ct_cyclic,
1313 1313                              ct->ct_heap);
1314 1314                          if (coargs->flags & COF_LONGLIST)  {
1315 1315                                  /* more info! */
1316 1316                                  mdb_printf(" %-7d %-7d %-?p %-?p %-?p"
1317 1317                                      " %-?lld %-?lld %-?p",
1318 1318                                      ct->ct_heap_num,  ct->ct_heap_max,
1319 1319                                      ct->ct_taskq, ct->ct_expired.ch_head,
1320 1320                                      ct->ct_queue.ch_head,
1321 1321                                      cotwd->ct_timeouts_pending,
1322 1322                                      cotwd->ct_allocations -
1323 1323                                      cotwd->ct_timeouts_pending,
1324 1324                                      ct->ct_mutex);
1325 1325                          }
1326 1326                  } else {
1327 1327                          /* address only */
1328 1328                          mdb_printf("%-0?p", addr);
1329 1329                  }
1330 1330                  mdb_printf("\n");
1331 1331                  if (coargs->flags & COF_TABLE) {
1332 1332                          return (WALK_NEXT);
1333 1333                  }
1334 1334          }
1335 1335  
1336 1336          coargs->ndx = index;
1337 1337          if (coargs->flags & COF_VERBOSE) {
1338 1338                  mdb_inc_indent(4);
1339 1339          }
1340 1340          /* keep digging. */
1341 1341          if (!(coargs->flags & COF_BYIDH)) {
1342 1342                  /* walk the list hash table */
1343 1343                  if (coargs->flags & COF_FREE) {
1344 1344                          clptr = ct->ct_lfree;
1345 1345                          coargs->bucket = 0;
1346 1346                          if (clptr == NULL) {
1347 1347                                  return (WALK_NEXT);
1348 1348                          }
1349 1349                          if (mdb_pwalk("callout_list", callout_list_cb, coargs,
1350 1350                              (uintptr_t)clptr) == -1) {
1351 1351                                  mdb_warn("cannot walk callout free list at %p",
1352 1352                                      clptr);
1353 1353                                  return (WALK_ERR);
1354 1354                          }
1355 1355                  } else {
1356 1356                          /* first print the expired list. */
1357 1357                          clptr = (callout_list_t *)ct->ct_expired.ch_head;
1358 1358                          if (clptr != NULL) {
1359 1359                                  coargs->bucket = -1;
1360 1360                                  if (mdb_pwalk("callout_list", callout_list_cb,
1361 1361                                      coargs, (uintptr_t)clptr) == -1) {
1362 1362                                          mdb_warn("cannot walk callout_list"
1363 1363                                              " at %p", clptr);
1364 1364                                          return (WALK_ERR);
1365 1365                                  }
1366 1366                          }
1367 1367                          /* then, print the callout queue */
1368 1368                          clptr = (callout_list_t *)ct->ct_queue.ch_head;
1369 1369                          if (clptr != NULL) {
1370 1370                                  coargs->bucket = -1;
1371 1371                                  if (mdb_pwalk("callout_list", callout_list_cb,
1372 1372                                      coargs, (uintptr_t)clptr) == -1) {
1373 1373                                          mdb_warn("cannot walk callout_list"
1374 1374                                              " at %p", clptr);
1375 1375                                          return (WALK_ERR);
1376 1376                                  }
1377 1377                          }
1378 1378                          for (i = 0; i < CALLOUT_BUCKETS; i++) {
1379 1379                                  if (ct->ct_clhash == NULL) {
1380 1380                                          /* nothing to do */
1381 1381                                          break;
1382 1382                                  }
1383 1383                                  if (cotwd->cot_clhash[i].ch_head == NULL) {
1384 1384                                          continue;
1385 1385                                  }
1386 1386                                  clptr = (callout_list_t *)
1387 1387                                      cotwd->cot_clhash[i].ch_head;
1388 1388                                  coargs->bucket = i;
1389 1389                                  /* walk list with callback routine. */
1390 1390                                  if (mdb_pwalk("callout_list", callout_list_cb,
1391 1391                                      coargs, (uintptr_t)clptr) == -1) {
1392 1392                                          mdb_warn("cannot walk callout_list"
1393 1393                                              " at %p", clptr);
1394 1394                                          return (WALK_ERR);
1395 1395                                  }
1396 1396                          }
1397 1397                  }
1398 1398          } else {
1399 1399                  /* walk the id hash table. */
1400 1400                  if (coargs->flags & COF_FREE) {
1401 1401                          coptr = ct->ct_free;
1402 1402                          coargs->bucket = 0;
1403 1403                          if (coptr == NULL) {
1404 1404                                  return (WALK_NEXT);
1405 1405                          }
1406 1406                          if (mdb_pwalk("callouts_byid", callouts_cb, coargs,
1407 1407                              (uintptr_t)coptr) == -1) {
1408 1408                                  mdb_warn("cannot walk callout id free list"
1409 1409                                      " at %p", coptr);
1410 1410                                  return (WALK_ERR);
1411 1411                          }
1412 1412                  } else {
1413 1413                          for (i = 0; i < CALLOUT_BUCKETS; i++) {
1414 1414                                  if (ct->ct_idhash == NULL) {
1415 1415                                          break;
1416 1416                                  }
1417 1417                                  coptr = (callout_t *)
1418 1418                                      cotwd->cot_idhash[i].ch_head;
1419 1419                                  if (coptr == NULL) {
1420 1420                                          continue;
1421 1421                                  }
1422 1422                                  coargs->bucket = i;
1423 1423  
1424 1424                                  /*
1425 1425                                   * walk callouts directly by id. For id
1426 1426                                   * chain, the callout list is just a header,
1427 1427                                   * so there's no need to walk it.
1428 1428                                   */
1429 1429                                  if (mdb_pwalk("callouts_byid", callouts_cb,
1430 1430                                      coargs, (uintptr_t)coptr) == -1) {
1431 1431                                          mdb_warn("cannot walk callouts at %p",
1432 1432                                              coptr);
1433 1433                                          return (WALK_ERR);
1434 1434                                  }
1435 1435                          }
1436 1436                  }
1437 1437          }
1438 1438          if (coargs->flags & COF_VERBOSE) {
1439 1439                  mdb_dec_indent(4);
1440 1440          }
1441 1441          return (WALK_NEXT);
1442 1442  }
1443 1443  
1444 1444  /*
1445 1445   * initialize some common info for both callout dcmds.
1446 1446   */
1447 1447  int
1448 1448  callout_common_init(callout_data_t *coargs)
1449 1449  {
1450 1450          /* we need a couple of things */
1451 1451          if (mdb_readvar(&(coargs->co_table), "callout_table") == -1) {
1452 1452                  mdb_warn("failed to read 'callout_table'");
1453 1453                  return (DCMD_ERR);
1454 1454          }
1455 1455          /* need to get now in nsecs. Approximate with hrtime vars */
1456 1456          if (mdb_readsym(&(coargs->now), sizeof (hrtime_t), "hrtime_last") !=
1457 1457              sizeof (hrtime_t)) {
1458 1458                  if (mdb_readsym(&(coargs->now), sizeof (hrtime_t),
1459 1459                      "hrtime_base") != sizeof (hrtime_t)) {
1460 1460                          mdb_warn("Could not determine current system time");
1461 1461                          return (DCMD_ERR);
1462 1462                  }
1463 1463          }
1464 1464  
1465 1465          if (mdb_readvar(&(coargs->ctbits), "callout_table_bits") == -1) {
1466 1466                  mdb_warn("failed to read 'callout_table_bits'");
1467 1467                  return (DCMD_ERR);
1468 1468          }
1469 1469          if (mdb_readvar(&(coargs->nsec_per_tick), "nsec_per_tick") == -1) {
1470 1470                  mdb_warn("failed to read 'nsec_per_tick'");
1471 1471                  return (DCMD_ERR);
1472 1472          }
1473 1473          return (DCMD_OK);
1474 1474  }
1475 1475  
1476 1476  /*
1477 1477   * dcmd to print callouts.  Optional addr limits to specific table.
1478 1478   * Parses lots of options that get passed to callbacks for walkers.
1479 1479   * Has it's own help function.
1480 1480   */
1481 1481  /*ARGSUSED*/
1482 1482  int
1483 1483  callout(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1484 1484  {
1485 1485          callout_data_t coargs;
1486 1486          /* getopts doesn't help much with stuff like this */
1487 1487          boolean_t Sflag, Cflag, tflag, aflag, bflag, dflag, kflag;
1488 1488          char *funcname = NULL;
1489 1489          char *paramstr = NULL;
1490 1490          uintptr_t Stmp, Ctmp;   /* for getopt. */
1491 1491          int retval;
1492 1492  
1493 1493          coargs.flags = COF_DEFAULT;
1494 1494          Sflag = Cflag = tflag = bflag = aflag = dflag = kflag = FALSE;
1495 1495          coargs.seqid = -1;
1496 1496  
1497 1497          if (mdb_getopts(argc, argv,
1498 1498              'r', MDB_OPT_CLRBITS, COF_NORM, &coargs.flags,
1499 1499              'n', MDB_OPT_CLRBITS, COF_REAL, &coargs.flags,
1500 1500              'l', MDB_OPT_CLRBITS, COF_SHORT, &coargs.flags,
1501 1501              's', MDB_OPT_CLRBITS, COF_LONG, &coargs.flags,
1502 1502              'x', MDB_OPT_SETBITS, COF_EXEC, &coargs.flags,
1503 1503              'h', MDB_OPT_SETBITS, COF_HIRES, &coargs.flags,
1504 1504              'B', MDB_OPT_SETBITS, COF_ABS, &coargs.flags,
1505 1505              'E', MDB_OPT_SETBITS, COF_EMPTY, &coargs.flags,
1506 1506              'd', MDB_OPT_SETBITS, 1, &dflag,
1507 1507              'C', MDB_OPT_UINTPTR_SET, &Cflag, &Ctmp,
1508 1508              'S', MDB_OPT_UINTPTR_SET, &Sflag, &Stmp,
1509 1509              't', MDB_OPT_UINTPTR_SET, &tflag, (uintptr_t *)&coargs.time,
1510 1510              'a', MDB_OPT_UINTPTR_SET, &aflag, (uintptr_t *)&coargs.atime,
1511 1511              'b', MDB_OPT_UINTPTR_SET, &bflag, (uintptr_t *)&coargs.btime,
1512 1512              'k', MDB_OPT_SETBITS, 1, &kflag,
1513 1513              'f', MDB_OPT_STR, &funcname,
1514 1514              'p', MDB_OPT_STR, ¶mstr,
1515 1515              'T', MDB_OPT_SETBITS, COF_TABLE, &coargs.flags,
1516 1516              'D', MDB_OPT_SETBITS, COF_EXPREL, &coargs.flags,
1517 1517              'L', MDB_OPT_SETBITS, COF_LIST, &coargs.flags,
1518 1518              'V', MDB_OPT_SETBITS, COF_VERBOSE, &coargs.flags,
1519 1519              'v', MDB_OPT_SETBITS, COF_LONGLIST, &coargs.flags,
1520 1520              'i', MDB_OPT_SETBITS, COF_BYIDH, &coargs.flags,
1521 1521              'F', MDB_OPT_SETBITS, COF_FREE, &coargs.flags,
1522 1522              'H', MDB_OPT_SETBITS, COF_HEAP, &coargs.flags,
1523 1523              'Q', MDB_OPT_SETBITS, COF_QUEUE, &coargs.flags,
1524 1524              'A', MDB_OPT_SETBITS, COF_ADDR, &coargs.flags,
1525 1525              NULL) != argc) {
1526 1526                  return (DCMD_USAGE);
1527 1527          }
1528 1528  
1529 1529          /* initialize from kernel variables */
1530 1530          if ((retval = callout_common_init(&coargs)) != DCMD_OK) {
1531 1531                  return (retval);
1532 1532          }
1533 1533  
1534 1534          /* do some option post-processing */
1535 1535          if (kflag) {
1536 1536                  coargs.time *= coargs.nsec_per_tick;
1537 1537                  coargs.atime *= coargs.nsec_per_tick;
1538 1538                  coargs.btime *= coargs.nsec_per_tick;
1539 1539          }
1540 1540  
1541 1541          if (dflag) {
1542 1542                  coargs.time += coargs.now;
1543 1543                  coargs.atime += coargs.now;
1544 1544                  coargs.btime += coargs.now;
1545 1545          }
1546 1546          if (Sflag) {
1547 1547                  if (flags & DCMD_ADDRSPEC) {
1548 1548                          mdb_printf("-S option conflicts with explicit"
1549 1549                              " address\n");
1550 1550                          return (DCMD_USAGE);
1551 1551                  }
1552 1552                  coargs.flags |= COF_SEQID;
1553 1553                  coargs.seqid = (int)Stmp;
1554 1554          }
1555 1555          if (Cflag) {
1556 1556                  if (flags & DCMD_ADDRSPEC) {
1557 1557                          mdb_printf("-C option conflicts with explicit"
1558 1558                              " address\n");
1559 1559                          return (DCMD_USAGE);
1560 1560                  }
1561 1561                  if (coargs.flags & COF_SEQID) {
1562 1562                          mdb_printf("-C and -S are mutually exclusive\n");
1563 1563                          return (DCMD_USAGE);
1564 1564                  }
1565 1565                  coargs.cpu = (cpu_t *)Ctmp;
1566 1566                  if (mdb_vread(&coargs.seqid, sizeof (processorid_t),
1567 1567                      (uintptr_t)&(coargs.cpu->cpu_seqid)) == -1) {
1568 1568                          mdb_warn("failed to read cpu_t at %p", Ctmp);
1569 1569                          return (DCMD_ERR);
1570 1570                  }
1571 1571                  coargs.flags |= COF_SEQID;
1572 1572          }
1573 1573          /* avoid null outputs. */
1574 1574          if (!(coargs.flags & (COF_REAL | COF_NORM))) {
1575 1575                  coargs.flags |= COF_REAL | COF_NORM;
1576 1576          }
1577 1577          if (!(coargs.flags & (COF_LONG | COF_SHORT))) {
1578 1578                  coargs.flags |= COF_LONG | COF_SHORT;
1579 1579          }
1580 1580          if (tflag) {
1581 1581                  if (aflag || bflag) {
1582 1582                          mdb_printf("-t and -a|b are mutually exclusive\n");
1583 1583                          return (DCMD_USAGE);
1584 1584                  }
1585 1585                  coargs.flags |= COF_TIME;
1586 1586          }
1587 1587          if (aflag) {
1588 1588                  coargs.flags |= COF_AFTER;
1589 1589          }
1590 1590          if (bflag) {
1591 1591                  coargs.flags |= COF_BEFORE;
1592 1592          }
1593 1593          if ((aflag && bflag) && (coargs.btime <= coargs.atime)) {
1594 1594                  mdb_printf("value for -a must be earlier than the value"
1595 1595                      " for -b.\n");
1596 1596                  return (DCMD_USAGE);
1597 1597          }
1598 1598  
1599 1599          if ((coargs.flags & COF_HEAP) && (coargs.flags & COF_QUEUE)) {
1600 1600                  mdb_printf("-H and -Q are mutually exclusive\n");
1601 1601                  return (DCMD_USAGE);
1602 1602          }
1603 1603  
1604 1604          if (funcname != NULL) {
1605 1605                  GElf_Sym sym;
1606 1606  
1607 1607                  if (mdb_lookup_by_name(funcname, &sym) != 0) {
1608 1608                          coargs.funcaddr = mdb_strtoull(funcname);
1609 1609                  } else {
1610 1610                          coargs.funcaddr = sym.st_value;
1611 1611                  }
1612 1612                  coargs.flags |= COF_FUNC;
1613 1613          }
1614 1614  
1615 1615          if (paramstr != NULL) {
1616 1616                  GElf_Sym sym;
1617 1617  
1618 1618                  if (mdb_lookup_by_name(paramstr, &sym) != 0) {
1619 1619                          coargs.param = mdb_strtoull(paramstr);
1620 1620                  } else {
1621 1621                          coargs.param = sym.st_value;
1622 1622                  }
1623 1623                  coargs.flags |= COF_PARAM;
1624 1624          }
1625 1625  
1626 1626          if (!(flags & DCMD_ADDRSPEC)) {
1627 1627                  /* don't pass "dot" if no addr. */
1628 1628                  addr = 0;
1629 1629          }
1630 1630          if (addr != 0) {
1631 1631                  /*
1632 1632                   * a callout table was specified. Ignore -r|n option
1633 1633                   * to avoid null output.
1634 1634                   */
1635 1635                  coargs.flags |= (COF_REAL | COF_NORM);
1636 1636          }
1637 1637  
1638 1638          if (DCMD_HDRSPEC(flags) || (coargs.flags & COF_VERBOSE)) {
1639 1639                  coargs.flags |= COF_THDR | COF_LHDR | COF_CHDR;
1640 1640          }
1641 1641          if (coargs.flags & COF_FREE) {
1642 1642                  coargs.flags |= COF_EMPTY;
1643 1643                  /* -F = free callouts, -FL = free lists */
1644 1644                  if (!(coargs.flags & COF_LIST)) {
1645 1645                          coargs.flags |= COF_BYIDH;
1646 1646                  }
1647 1647          }
1648 1648  
1649 1649          /* walk table, using specialized callback routine. */
1650 1650          if (mdb_pwalk("callout_table", callout_t_cb, &coargs, addr) == -1) {
1651 1651                  mdb_warn("cannot walk callout_table");
1652 1652                  return (DCMD_ERR);
1653 1653          }
1654 1654          return (DCMD_OK);
1655 1655  }
1656 1656  
1657 1657  
1658 1658  /*
1659 1659   * Given an extended callout id, dump its information.
1660 1660   */
1661 1661  /*ARGSUSED*/
1662 1662  int
1663 1663  calloutid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1664 1664  {
1665 1665          callout_data_t coargs;
1666 1666          callout_table_t *ctptr;
1667 1667          callout_table_t ct;
1668 1668          callout_id_t coid;
1669 1669          callout_t *coptr;
1670 1670          int tableid;
1671 1671          callout_id_t xid;
1672 1672          ulong_t idhash;
1673 1673          int i, retval;
1674 1674          const mdb_arg_t *arg;
1675 1675          size_t size;
1676 1676          callout_hash_t cot_idhash[CALLOUT_BUCKETS];
1677 1677  
1678 1678          coargs.flags = COF_DEFAULT | COF_BYIDH;
1679 1679          i = mdb_getopts(argc, argv,
1680 1680              'd', MDB_OPT_SETBITS, COF_DECODE, &coargs.flags,
1681 1681              'v', MDB_OPT_SETBITS, COF_LONGLIST, &coargs.flags,
1682 1682              NULL);
1683 1683          argc -= i;
1684 1684          argv += i;
1685 1685  
1686 1686          if (argc != 1) {
1687 1687                  return (DCMD_USAGE);
1688 1688          }
1689 1689          arg = &argv[0];
1690 1690  
1691 1691          if (arg->a_type == MDB_TYPE_IMMEDIATE) {
1692 1692                  xid = arg->a_un.a_val;
1693 1693          } else {
1694 1694                  xid = (callout_id_t)mdb_strtoull(arg->a_un.a_str);
1695 1695          }
1696 1696  
1697 1697          if (DCMD_HDRSPEC(flags)) {
1698 1698                  coargs.flags |= COF_CHDR;
1699 1699          }
1700 1700  
1701 1701  
1702 1702          /* initialize from kernel variables */
1703 1703          if ((retval = callout_common_init(&coargs)) != DCMD_OK) {
1704 1704                  return (retval);
1705 1705          }
1706 1706  
1707 1707          /* we must massage the environment so that the macros will play nice */
1708 1708  #define callout_table_mask      ((1 << coargs.ctbits) - 1)
1709 1709  #define callout_table_bits      coargs.ctbits
1710 1710  #define nsec_per_tick           coargs.nsec_per_tick
1711 1711          tableid = CALLOUT_ID_TO_TABLE(xid);
1712 1712          idhash = CALLOUT_IDHASH(xid);
1713 1713  #undef  callouts_table_bits
1714 1714  #undef  callout_table_mask
1715 1715  #undef  nsec_per_tick
1716 1716          coid = CO_PLAIN_ID(xid);
1717 1717  
1718 1718          if (flags & DCMD_ADDRSPEC) {
1719 1719                  mdb_printf("calloutid does not accept explicit address.\n");
1720 1720                  return (DCMD_USAGE);
1721 1721          }
1722 1722  
1723 1723          if (coargs.flags & COF_DECODE) {
1724 1724                  if (DCMD_HDRSPEC(flags)) {
1725 1725                          mdb_printf("%<u>%3s %1s %2s %-?s %-6s %</u>\n",
1726 1726                              "SEQ", "T", "XL", "XID", "IDHASH");
1727 1727                  }
1728 1728                  mdb_printf("%-3d %1s %1s%1s %-?llx %-6d\n",
1729 1729                      TABLE_TO_SEQID(tableid),
1730 1730                      co_typenames[tableid & CALLOUT_TYPE_MASK],
1731 1731                      (xid & CALLOUT_EXECUTING) ? "X" : " ",
1732 1732                      (xid & CALLOUT_LONGTERM) ? "L" : " ",
1733 1733                      (long long)coid, idhash);
1734 1734                  return (DCMD_OK);
1735 1735          }
1736 1736  
1737 1737          /* get our table. Note this relies on the types being correct */
1738 1738          ctptr = coargs.co_table + tableid;
1739 1739          if (mdb_vread(&ct, sizeof (callout_table_t), (uintptr_t)ctptr) == -1) {
1740 1740                  mdb_warn("failed to read callout_table at %p", ctptr);
1741 1741                  return (DCMD_ERR);
1742 1742          }
1743 1743          size = sizeof (callout_hash_t) * CALLOUT_BUCKETS;
1744 1744          if (ct.ct_idhash != NULL) {
1745 1745                  if (mdb_vread(&(cot_idhash), size,
1746 1746                      (uintptr_t)ct.ct_idhash) == -1) {
1747 1747                          mdb_warn("failed to read id_hash at %p",
1748 1748                              ct.ct_idhash);
1749 1749                          return (WALK_ERR);
1750 1750                  }
1751 1751          }
1752 1752  
1753 1753          /* callout at beginning of hash chain */
1754 1754          if (ct.ct_idhash == NULL) {
1755 1755                  mdb_printf("id hash chain for this xid is empty\n");
1756 1756                  return (DCMD_ERR);
1757 1757          }
1758 1758          coptr = (callout_t *)cot_idhash[idhash].ch_head;
1759 1759          if (coptr == NULL) {
1760 1760                  mdb_printf("id hash chain for this xid is empty\n");
1761 1761                  return (DCMD_ERR);
1762 1762          }
1763 1763  
1764 1764          coargs.ndx = tableid;
1765 1765          coargs.bucket = idhash;
1766 1766  
1767 1767          /* use the walker, luke */
1768 1768          if (mdb_pwalk("callouts_byid", callouts_cb, &coargs,
1769 1769              (uintptr_t)coptr) == -1) {
1770 1770                  mdb_warn("cannot walk callouts at %p", coptr);
1771 1771                  return (WALK_ERR);
1772 1772          }
1773 1773  
1774 1774          return (DCMD_OK);
1775 1775  }
1776 1776  
1777 1777  void
1778 1778  callout_help(void)
1779 1779  {
1780 1780          mdb_printf("callout: display callouts.\n"
1781 1781              "Given a callout table address, display callouts from table.\n"
1782 1782              "Without an address, display callouts from all tables.\n"
1783 1783              "options:\n"
1784 1784              " -r|n : limit display to (r)ealtime or (n)ormal type callouts\n"
1785 1785              " -s|l : limit display to (s)hort-term ids or (l)ong-term ids\n"
1786 1786              " -x : limit display to callouts which are executing\n"
1787 1787              " -h : limit display to callouts based on hrestime\n"
1788 1788              " -B : limit display to callouts based on absolute time\n"
1789 1789              " -t|a|b nsec: limit display to callouts that expire a(t) time,"
1790 1790              " (a)fter time,\n     or (b)efore time. Use -a and -b together "
1791 1791              " to specify a range.\n     For \"now\", use -d[t|a|b] 0.\n"
1792 1792              " -d : interpret time option to -t|a|b as delta from current time\n"
1793 1793              " -k : use ticks instead of nanoseconds as arguments to"
1794 1794              " -t|a|b. Note that\n     ticks are less accurate and may not"
1795 1795              " match other tick times (ie: lbolt).\n"
1796 1796              " -D : display exiration time as delta from current time\n"
1797 1797              " -S seqid : limit display to callouts for this cpu sequence id\n"
1798 1798              " -C addr :  limit display to callouts for this cpu pointer\n"
1799 1799              " -f name|addr : limit display to callouts with this function\n"
1800 1800              " -p name|addr : limit display to callouts functions with this"
1801 1801              " parameter\n"
1802 1802              " -T : display the callout table itself, instead of callouts\n"
1803 1803              " -L : display callout lists instead of callouts\n"
1804 1804              " -E : with -T or L, display empty data structures.\n"
1805 1805              " -i : traverse callouts by id hash instead of list hash\n"
1806 1806              " -F : walk free callout list (free list with -i) instead\n"
1807 1807              " -v : display more info for each item\n"
1808 1808              " -V : show details of each level of info as it is traversed\n"
1809 1809              " -H : limit display to callouts in the callout heap\n"
1810 1810              " -Q : limit display to callouts in the callout queue\n"
1811 1811              " -A : show only addresses. Useful for pipelines.\n");
1812 1812  }
1813 1813  
1814 1814  void
1815 1815  calloutid_help(void)
1816 1816  {
1817 1817          mdb_printf("calloutid: display callout by id.\n"
1818 1818              "Given an extended callout id, display the callout infomation.\n"
1819 1819              "options:\n"
1820 1820              " -d : do not dereference callout, just decode the id.\n"
1821 1821              " -v : verbose display more info about the callout\n");
1822 1822  }
1823 1823  
1824 1824  /*ARGSUSED*/
1825 1825  int
1826 1826  class(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1827 1827  {
1828 1828          long num_classes, i;
1829 1829          sclass_t *class_tbl;
1830 1830          GElf_Sym g_sclass;
1831 1831          char class_name[PC_CLNMSZ];
1832 1832          size_t tbl_size;
1833 1833  
1834 1834          if (mdb_lookup_by_name("sclass", &g_sclass) == -1) {
1835 1835                  mdb_warn("failed to find symbol sclass\n");
1836 1836                  return (DCMD_ERR);
1837 1837          }
1838 1838  
1839 1839          tbl_size = (size_t)g_sclass.st_size;
1840 1840          num_classes = tbl_size / (sizeof (sclass_t));
1841 1841          class_tbl = mdb_alloc(tbl_size, UM_SLEEP | UM_GC);
1842 1842  
1843 1843          if (mdb_readsym(class_tbl, tbl_size, "sclass") == -1) {
1844 1844                  mdb_warn("failed to read sclass");
1845 1845                  return (DCMD_ERR);
1846 1846          }
1847 1847  
1848 1848          mdb_printf("%<u>%4s %-10s %-24s %-24s%</u>\n", "SLOT", "NAME",
1849 1849              "INIT FCN", "CLASS FCN");
1850 1850  
1851 1851          for (i = 0; i < num_classes; i++) {
1852 1852                  if (mdb_vread(class_name, sizeof (class_name),
1853 1853                      (uintptr_t)class_tbl[i].cl_name) == -1)
1854 1854                          (void) strcpy(class_name, "???");
1855 1855  
1856 1856                  mdb_printf("%4ld %-10s %-24a %-24a\n", i, class_name,
1857 1857                      class_tbl[i].cl_init, class_tbl[i].cl_funcs);
1858 1858          }
1859 1859  
1860 1860          return (DCMD_OK);
1861 1861  }
1862 1862  
1863 1863  #define FSNAMELEN       32      /* Max len of FS name we read from vnodeops */
1864 1864  
1865 1865  int
1866 1866  vnode2path(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1867 1867  {
1868 1868          uintptr_t rootdir;
1869 1869          vnode_t vn;
1870 1870          char buf[MAXPATHLEN];
1871 1871  
1872 1872          uint_t opt_F = FALSE;
1873 1873  
1874 1874          if (mdb_getopts(argc, argv,
1875 1875              'F', MDB_OPT_SETBITS, TRUE, &opt_F, NULL) != argc)
1876 1876                  return (DCMD_USAGE);
1877 1877  
1878 1878          if (!(flags & DCMD_ADDRSPEC)) {
1879 1879                  mdb_warn("expected explicit vnode_t address before ::\n");
1880 1880                  return (DCMD_USAGE);
1881 1881          }
1882 1882  
1883 1883          if (mdb_readvar(&rootdir, "rootdir") == -1) {
1884 1884                  mdb_warn("failed to read rootdir");
1885 1885                  return (DCMD_ERR);
1886 1886          }
1887 1887  
1888 1888          if (mdb_vnode2path(addr, buf, sizeof (buf)) == -1)
1889 1889                  return (DCMD_ERR);
1890 1890  
1891 1891          if (*buf == '\0') {
1892 1892                  mdb_printf("??\n");
1893 1893                  return (DCMD_OK);
1894 1894          }
1895 1895  
1896 1896          mdb_printf("%s", buf);
1897 1897          if (opt_F && buf[strlen(buf)-1] != '/' &&
1898 1898              mdb_vread(&vn, sizeof (vn), addr) == sizeof (vn))
1899 1899                  mdb_printf("%c", mdb_vtype2chr(vn.v_type, 0));
1900 1900          mdb_printf("\n");
1901 1901  
1902 1902          return (DCMD_OK);
1903 1903  }
1904 1904  
1905 1905  int
1906 1906  ld_walk_init(mdb_walk_state_t *wsp)
1907 1907  {
1908 1908          wsp->walk_data = (void *)wsp->walk_addr;
1909 1909          return (WALK_NEXT);
1910 1910  }
1911 1911  
1912 1912  int
1913 1913  ld_walk_step(mdb_walk_state_t *wsp)
1914 1914  {
1915 1915          int status;
1916 1916          lock_descriptor_t ld;
1917 1917  
1918 1918          if (mdb_vread(&ld, sizeof (lock_descriptor_t), wsp->walk_addr) == -1) {
1919 1919                  mdb_warn("couldn't read lock_descriptor_t at %p\n",
1920 1920                      wsp->walk_addr);
1921 1921                  return (WALK_ERR);
1922 1922          }
1923 1923  
1924 1924          status = wsp->walk_callback(wsp->walk_addr, &ld, wsp->walk_cbdata);
1925 1925          if (status == WALK_ERR)
1926 1926                  return (WALK_ERR);
1927 1927  
1928 1928          wsp->walk_addr = (uintptr_t)ld.l_next;
1929 1929          if (wsp->walk_addr == (uintptr_t)wsp->walk_data)
1930 1930                  return (WALK_DONE);
1931 1931  
1932 1932          return (status);
1933 1933  }
1934 1934  
1935 1935  int
1936 1936  lg_walk_init(mdb_walk_state_t *wsp)
1937 1937  {
1938 1938          GElf_Sym sym;
1939 1939  
1940 1940          if (mdb_lookup_by_name("lock_graph", &sym) == -1) {
1941 1941                  mdb_warn("failed to find symbol 'lock_graph'\n");
1942 1942                  return (WALK_ERR);
1943 1943          }
1944 1944  
1945 1945          wsp->walk_addr = (uintptr_t)sym.st_value;
1946 1946          wsp->walk_data = (void *)(uintptr_t)(sym.st_value + sym.st_size);
1947 1947  
1948 1948          return (WALK_NEXT);
1949 1949  }
1950 1950  
1951 1951  typedef struct lg_walk_data {
1952 1952          uintptr_t startaddr;
1953 1953          mdb_walk_cb_t callback;
1954 1954          void *data;
1955 1955  } lg_walk_data_t;
1956 1956  
1957 1957  /*
1958 1958   * We can't use ::walk lock_descriptor directly, because the head of each graph
1959 1959   * is really a dummy lock.  Rather than trying to dynamically determine if this
1960 1960   * is a dummy node or not, we just filter out the initial element of the
1961 1961   * list.
1962 1962   */
1963 1963  static int
1964 1964  lg_walk_cb(uintptr_t addr, const void *data, void *priv)
1965 1965  {
1966 1966          lg_walk_data_t *lw = priv;
1967 1967  
1968 1968          if (addr != lw->startaddr)
1969 1969                  return (lw->callback(addr, data, lw->data));
1970 1970  
1971 1971          return (WALK_NEXT);
1972 1972  }
1973 1973  
1974 1974  int
1975 1975  lg_walk_step(mdb_walk_state_t *wsp)
1976 1976  {
1977 1977          graph_t *graph;
1978 1978          lg_walk_data_t lw;
1979 1979  
1980 1980          if (wsp->walk_addr >= (uintptr_t)wsp->walk_data)
1981 1981                  return (WALK_DONE);
1982 1982  
1983 1983          if (mdb_vread(&graph, sizeof (graph), wsp->walk_addr) == -1) {
1984 1984                  mdb_warn("failed to read graph_t at %p", wsp->walk_addr);
1985 1985                  return (WALK_ERR);
1986 1986          }
1987 1987  
1988 1988          wsp->walk_addr += sizeof (graph);
1989 1989  
1990 1990          if (graph == NULL)
1991 1991                  return (WALK_NEXT);
1992 1992  
1993 1993          lw.callback = wsp->walk_callback;
1994 1994          lw.data = wsp->walk_cbdata;
1995 1995  
1996 1996          lw.startaddr = (uintptr_t)&(graph->active_locks);
1997 1997          if (mdb_pwalk("lock_descriptor", lg_walk_cb, &lw, lw.startaddr)) {
1998 1998                  mdb_warn("couldn't walk lock_descriptor at %p\n", lw.startaddr);
1999 1999                  return (WALK_ERR);
2000 2000          }
2001 2001  
2002 2002          lw.startaddr = (uintptr_t)&(graph->sleeping_locks);
2003 2003          if (mdb_pwalk("lock_descriptor", lg_walk_cb, &lw, lw.startaddr)) {
2004 2004                  mdb_warn("couldn't walk lock_descriptor at %p\n", lw.startaddr);
2005 2005                  return (WALK_ERR);
2006 2006          }
2007 2007  
2008 2008          return (WALK_NEXT);
2009 2009  }
2010 2010  
2011 2011  /*
2012 2012   * The space available for the path corresponding to the locked vnode depends
2013 2013   * on whether we are printing 32- or 64-bit addresses.
2014 2014   */
2015 2015  #ifdef _LP64
2016 2016  #define LM_VNPATHLEN    20
2017 2017  #else
2018 2018  #define LM_VNPATHLEN    30
2019 2019  #endif
2020 2020  
2021 2021  typedef struct mdb_lminfo_proc {
2022 2022          struct {
2023 2023                  char            u_comm[MAXCOMLEN + 1];
2024 2024          } p_user;
2025 2025  } mdb_lminfo_proc_t;
2026 2026  
2027 2027  /*ARGSUSED*/
2028 2028  static int
2029 2029  lminfo_cb(uintptr_t addr, const void *data, void *priv)
2030 2030  {
2031 2031          const lock_descriptor_t *ld = data;
2032 2032          char buf[LM_VNPATHLEN];
2033 2033          mdb_lminfo_proc_t p;
2034 2034          uintptr_t paddr = 0;
2035 2035  
2036 2036          if (ld->l_flock.l_pid != 0)
2037 2037                  paddr = mdb_pid2proc(ld->l_flock.l_pid, NULL);
2038 2038  
2039 2039          if (paddr != 0)
2040 2040                  mdb_ctf_vread(&p, "proc_t", "mdb_lminfo_proc_t", paddr, 0);
2041 2041  
2042 2042          mdb_printf("%-?p %2s %04x %6d %-16s %-?p ",
2043 2043              addr, ld->l_type == F_RDLCK ? "RD" :
2044 2044              ld->l_type == F_WRLCK ? "WR" : "??",
2045 2045              ld->l_state, ld->l_flock.l_pid,
2046 2046              ld->l_flock.l_pid == 0 ? "<kernel>" :
2047 2047              paddr == 0 ? "<defunct>" : p.p_user.u_comm, ld->l_vnode);
2048 2048  
2049 2049          mdb_vnode2path((uintptr_t)ld->l_vnode, buf,
2050 2050              sizeof (buf));
2051 2051          mdb_printf("%s\n", buf);
2052 2052  
2053 2053          return (WALK_NEXT);
2054 2054  }
2055 2055  
2056 2056  /*ARGSUSED*/
2057 2057  int
2058 2058  lminfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2059 2059  {
2060 2060          if (DCMD_HDRSPEC(flags))
2061 2061                  mdb_printf("%<u>%-?s %2s %4s %6s %-16s %-?s %s%</u>\n",
2062 2062                      "ADDR", "TP", "FLAG", "PID", "COMM", "VNODE", "PATH");
2063 2063  
2064 2064          return (mdb_pwalk("lock_graph", lminfo_cb, NULL, 0));
2065 2065  }
2066 2066  
2067 2067  typedef struct mdb_whereopen {
2068 2068          uint_t mwo_flags;
2069 2069          uintptr_t mwo_target;
2070 2070          boolean_t mwo_found;
2071 2071  } mdb_whereopen_t;
2072 2072  
2073 2073  /*ARGSUSED*/
2074 2074  int
2075 2075  whereopen_fwalk(uintptr_t addr, const void *farg, void *arg)
2076 2076  {
2077 2077          const struct file *f = farg;
2078 2078          mdb_whereopen_t *mwo = arg;
2079 2079  
2080 2080          if ((uintptr_t)f->f_vnode == mwo->mwo_target) {
2081 2081                  if ((mwo->mwo_flags & DCMD_PIPE_OUT) == 0 &&
2082 2082                      !mwo->mwo_found) {
2083 2083                          mdb_printf("file %p\n", addr);
2084 2084                  }
2085 2085                  mwo->mwo_found = B_TRUE;
2086 2086          }
2087 2087  
2088 2088          return (WALK_NEXT);
2089 2089  }
2090 2090  
2091 2091  /*ARGSUSED*/
2092 2092  int
2093 2093  whereopen_pwalk(uintptr_t addr, const void *ignored, void *arg)
2094 2094  {
2095 2095          mdb_whereopen_t *mwo = arg;
2096 2096  
2097 2097          mwo->mwo_found = B_FALSE;
2098 2098          if (mdb_pwalk("file", whereopen_fwalk, mwo, addr) == -1) {
2099 2099                  mdb_warn("couldn't file walk proc %p", addr);
2100 2100                  return (WALK_ERR);
2101 2101          }
2102 2102  
2103 2103          if (mwo->mwo_found) {
2104 2104                  mdb_printf("%p\n", addr);
2105 2105          }
2106 2106  
2107 2107          return (WALK_NEXT);
2108 2108  }
2109 2109  
2110 2110  /*ARGSUSED*/
2111 2111  int
2112 2112  whereopen(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2113 2113  {
2114 2114          mdb_whereopen_t mwo;
2115 2115  
2116 2116          if (!(flags & DCMD_ADDRSPEC) || addr == 0)
2117 2117                  return (DCMD_USAGE);
2118 2118  
2119 2119          mwo.mwo_flags = flags;
2120 2120          mwo.mwo_target = addr;
2121 2121          mwo.mwo_found = B_FALSE;
2122 2122  
2123 2123          if (mdb_walk("proc", whereopen_pwalk, &mwo) == -1) {
2124 2124                  mdb_warn("can't proc walk");
2125 2125                  return (DCMD_ERR);
2126 2126          }
2127 2127  
2128 2128          return (DCMD_OK);
2129 2129  }
2130 2130  
2131 2131  typedef struct datafmt {
2132 2132          char    *hdr1;
2133 2133          char    *hdr2;
2134 2134          char    *dashes;
2135 2135          char    *fmt;
2136 2136  } datafmt_t;
2137 2137  
2138 2138  static datafmt_t kmemfmt[] = {
2139 2139          { "cache                    ", "name                     ",
2140 2140          "-------------------------", "%-25s "                           },
2141 2141          { "   buf",     "  size",       "------",       "%6u "          },
2142 2142          { "   buf",     "in use",       "------",       "%6u "          },
2143 2143          { "   buf",     " total",       "------",       "%6u "          },
2144 2144          { "   memory",  "   in use",    "----------",   "%10lu%c "      },
2145 2145          { "    alloc",  "  succeed",    "---------",    "%9u "          },
2146 2146          { "alloc",      " fail",        "-----",        "%5u "          },
2147 2147          { NULL,         NULL,           NULL,           NULL            }
2148 2148  };
2149 2149  
2150 2150  static datafmt_t vmemfmt[] = {
2151 2151          { "vmem                     ", "name                     ",
2152 2152          "-------------------------", "%-*s "                            },
2153 2153          { "   memory",  "   in use",    "----------",   "%9llu%c "      },
2154 2154          { "    memory", "     total",   "-----------",  "%10llu%c "     },
2155 2155          { "   memory",  "   import",    "----------",   "%9llu%c "      },
2156 2156          { "    alloc",  "  succeed",    "---------",    "%9llu "        },
2157 2157          { "alloc",      " fail",        "-----",        "%5llu "        },
2158 2158          { NULL,         NULL,           NULL,           NULL            }
2159 2159  };
2160 2160  
2161 2161  /*ARGSUSED*/
2162 2162  static int
2163 2163  kmastat_cpu_avail(uintptr_t addr, const kmem_cpu_cache_t *ccp, int *avail)
2164 2164  {
2165 2165          short rounds, prounds;
2166 2166  
2167 2167          if (KMEM_DUMPCC(ccp)) {
2168 2168                  rounds = ccp->cc_dump_rounds;
2169 2169                  prounds = ccp->cc_dump_prounds;
2170 2170          } else {
2171 2171                  rounds = ccp->cc_rounds;
2172 2172                  prounds = ccp->cc_prounds;
2173 2173          }
2174 2174          if (rounds > 0)
2175 2175                  *avail += rounds;
2176 2176          if (prounds > 0)
2177 2177                  *avail += prounds;
2178 2178  
2179 2179          return (WALK_NEXT);
2180 2180  }
2181 2181  
2182 2182  /*ARGSUSED*/
2183 2183  static int
2184 2184  kmastat_cpu_alloc(uintptr_t addr, const kmem_cpu_cache_t *ccp, int *alloc)
2185 2185  {
2186 2186          *alloc += ccp->cc_alloc;
2187 2187  
2188 2188          return (WALK_NEXT);
2189 2189  }
2190 2190  
2191 2191  /*ARGSUSED*/
2192 2192  static int
2193 2193  kmastat_slab_avail(uintptr_t addr, const kmem_slab_t *sp, int *avail)
2194 2194  {
2195 2195          *avail += sp->slab_chunks - sp->slab_refcnt;
2196 2196  
2197 2197          return (WALK_NEXT);
2198 2198  }
2199 2199  
2200 2200  typedef struct kmastat_vmem {
2201 2201          uintptr_t kv_addr;
2202 2202          struct kmastat_vmem *kv_next;
2203 2203          size_t kv_meminuse;
2204 2204          int kv_alloc;
2205 2205          int kv_fail;
2206 2206  } kmastat_vmem_t;
2207 2207  
2208 2208  typedef struct kmastat_args {
2209 2209          kmastat_vmem_t **ka_kvpp;
2210 2210          uint_t ka_shift;
2211 2211  } kmastat_args_t;
2212 2212  
2213 2213  static int
2214 2214  kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_args_t *kap)
2215 2215  {
2216 2216          kmastat_vmem_t **kvpp = kap->ka_kvpp;
2217 2217          kmastat_vmem_t *kv;
2218 2218          datafmt_t *dfp = kmemfmt;
2219 2219          int magsize;
2220 2220  
2221 2221          int avail, alloc, total;
2222 2222          size_t meminuse = (cp->cache_slab_create - cp->cache_slab_destroy) *
2223 2223              cp->cache_slabsize;
2224 2224  
2225 2225          mdb_walk_cb_t cpu_avail = (mdb_walk_cb_t)kmastat_cpu_avail;
2226 2226          mdb_walk_cb_t cpu_alloc = (mdb_walk_cb_t)kmastat_cpu_alloc;
2227 2227          mdb_walk_cb_t slab_avail = (mdb_walk_cb_t)kmastat_slab_avail;
2228 2228  
2229 2229          magsize = kmem_get_magsize(cp);
2230 2230  
2231 2231          alloc = cp->cache_slab_alloc + cp->cache_full.ml_alloc;
2232 2232          avail = cp->cache_full.ml_total * magsize;
2233 2233          total = cp->cache_buftotal;
2234 2234  
2235 2235          (void) mdb_pwalk("kmem_cpu_cache", cpu_alloc, &alloc, addr);
2236 2236          (void) mdb_pwalk("kmem_cpu_cache", cpu_avail, &avail, addr);
2237 2237          (void) mdb_pwalk("kmem_slab_partial", slab_avail, &avail, addr);
2238 2238  
2239 2239          for (kv = *kvpp; kv != NULL; kv = kv->kv_next) {
2240 2240                  if (kv->kv_addr == (uintptr_t)cp->cache_arena)
2241 2241                          goto out;
2242 2242          }
2243 2243  
2244 2244          kv = mdb_zalloc(sizeof (kmastat_vmem_t), UM_SLEEP | UM_GC);
2245 2245          kv->kv_next = *kvpp;
2246 2246          kv->kv_addr = (uintptr_t)cp->cache_arena;
2247 2247          *kvpp = kv;
2248 2248  out:
2249 2249          kv->kv_meminuse += meminuse;
2250 2250          kv->kv_alloc += alloc;
2251 2251          kv->kv_fail += cp->cache_alloc_fail;
2252 2252  
2253 2253          mdb_printf((dfp++)->fmt, cp->cache_name);
2254 2254          mdb_printf((dfp++)->fmt, cp->cache_bufsize);
2255 2255          mdb_printf((dfp++)->fmt, total - avail);
2256 2256          mdb_printf((dfp++)->fmt, total);
2257 2257          mdb_printf((dfp++)->fmt, meminuse >> kap->ka_shift,
2258 2258              kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' :
2259 2259              kap->ka_shift == KILOS ? 'K' : 'B');
2260 2260          mdb_printf((dfp++)->fmt, alloc);
2261 2261          mdb_printf((dfp++)->fmt, cp->cache_alloc_fail);
2262 2262          mdb_printf("\n");
2263 2263  
2264 2264          return (WALK_NEXT);
2265 2265  }
2266 2266  
2267 2267  static int
2268 2268  kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap)
2269 2269  {
2270 2270          kmastat_vmem_t *kv = *kap->ka_kvpp;
2271 2271          size_t len;
2272 2272  
2273 2273          while (kv != NULL && kv->kv_addr != addr)
2274 2274                  kv = kv->kv_next;
2275 2275  
2276 2276          if (kv == NULL || kv->kv_alloc == 0)
2277 2277                  return (WALK_NEXT);
2278 2278  
2279 2279          len = MIN(17, strlen(v->vm_name));
2280 2280  
2281 2281          mdb_printf("Total [%s]%*s %6s %6s %6s %10lu%c %9u %5u\n", v->vm_name,
2282 2282              17 - len, "", "", "", "",
2283 2283              kv->kv_meminuse >> kap->ka_shift,
2284 2284              kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' :
2285 2285              kap->ka_shift == KILOS ? 'K' : 'B', kv->kv_alloc, kv->kv_fail);
2286 2286  
2287 2287          return (WALK_NEXT);
2288 2288  }
2289 2289  
2290 2290  /*ARGSUSED*/
2291 2291  static int
2292 2292  kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp)
2293 2293  {
2294 2294          datafmt_t *dfp = vmemfmt;
2295 2295          const vmem_kstat_t *vkp = &v->vm_kstat;
2296 2296          uintptr_t paddr;
2297 2297          vmem_t parent;
2298 2298          int ident = 0;
2299 2299  
2300 2300          for (paddr = (uintptr_t)v->vm_source; paddr != 0; ident += 4) {
2301 2301                  if (mdb_vread(&parent, sizeof (parent), paddr) == -1) {
2302 2302                          mdb_warn("couldn't trace %p's ancestry", addr);
2303 2303                          ident = 0;
2304 2304                          break;
2305 2305                  }
2306 2306                  paddr = (uintptr_t)parent.vm_source;
2307 2307          }
2308 2308  
2309 2309          mdb_printf("%*s", ident, "");
2310 2310          mdb_printf((dfp++)->fmt, 25 - ident, v->vm_name);
2311 2311          mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64 >> *shiftp,
2312 2312              *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
2313 2313              *shiftp == KILOS ? 'K' : 'B');
2314 2314          mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64 >> *shiftp,
2315 2315              *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
2316 2316              *shiftp == KILOS ? 'K' : 'B');
2317 2317          mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64 >> *shiftp,
2318 2318              *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
2319 2319              *shiftp == KILOS ? 'K' : 'B');
2320 2320          mdb_printf((dfp++)->fmt, vkp->vk_alloc.value.ui64);
2321 2321          mdb_printf((dfp++)->fmt, vkp->vk_fail.value.ui64);
2322 2322  
2323 2323          mdb_printf("\n");
2324 2324  
2325 2325          return (WALK_NEXT);
2326 2326  }
2327 2327  
2328 2328  /*ARGSUSED*/
2329 2329  int
2330 2330  kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2331 2331  {
2332 2332          kmastat_vmem_t *kv = NULL;
2333 2333          datafmt_t *dfp;
2334 2334          kmastat_args_t ka;
2335 2335  
2336 2336          ka.ka_shift = 0;
2337 2337          if (mdb_getopts(argc, argv,
2338 2338              'k', MDB_OPT_SETBITS, KILOS, &ka.ka_shift,
2339 2339              'm', MDB_OPT_SETBITS, MEGS, &ka.ka_shift,
2340 2340              'g', MDB_OPT_SETBITS, GIGS, &ka.ka_shift, NULL) != argc)
2341 2341                  return (DCMD_USAGE);
2342 2342  
2343 2343          for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
2344 2344                  mdb_printf("%s ", dfp->hdr1);
2345 2345          mdb_printf("\n");
2346 2346  
2347 2347          for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
2348 2348                  mdb_printf("%s ", dfp->hdr2);
2349 2349          mdb_printf("\n");
2350 2350  
2351 2351          for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
2352 2352                  mdb_printf("%s ", dfp->dashes);
2353 2353          mdb_printf("\n");
2354 2354  
2355 2355          ka.ka_kvpp = &kv;
2356 2356          if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &ka) == -1) {
2357 2357                  mdb_warn("can't walk 'kmem_cache'");
2358 2358                  return (DCMD_ERR);
2359 2359          }
2360 2360  
2361 2361          for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
2362 2362                  mdb_printf("%s ", dfp->dashes);
2363 2363          mdb_printf("\n");
2364 2364  
2365 2365          if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, &ka) == -1) {
2366 2366                  mdb_warn("can't walk 'vmem'");
2367 2367                  return (DCMD_ERR);
2368 2368          }
2369 2369  
2370 2370          for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
2371 2371                  mdb_printf("%s ", dfp->dashes);
2372 2372          mdb_printf("\n");
2373 2373  
2374 2374          mdb_printf("\n");
2375 2375  
2376 2376          for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2377 2377                  mdb_printf("%s ", dfp->hdr1);
2378 2378          mdb_printf("\n");
2379 2379  
2380 2380          for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2381 2381                  mdb_printf("%s ", dfp->hdr2);
2382 2382          mdb_printf("\n");
2383 2383  
2384 2384          for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2385 2385                  mdb_printf("%s ", dfp->dashes);
2386 2386          mdb_printf("\n");
2387 2387  
2388 2388          if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, &ka.ka_shift) == -1) {
2389 2389                  mdb_warn("can't walk 'vmem'");
2390 2390                  return (DCMD_ERR);
2391 2391          }
2392 2392  
2393 2393          for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2394 2394                  mdb_printf("%s ", dfp->dashes);
2395 2395          mdb_printf("\n");
2396 2396          return (DCMD_OK);
2397 2397  }
2398 2398  
2399 2399  /*
2400 2400   * Our ::kgrep callback scans the entire kernel VA space (kas).  kas is made
2401 2401   * up of a set of 'struct seg's.  We could just scan each seg en masse, but
2402 2402   * unfortunately, a few of the segs are both large and sparse, so we could
2403 2403   * spend quite a bit of time scanning VAs which have no backing pages.
2404 2404   *
2405 2405   * So for the few very sparse segs, we skip the segment itself, and scan
2406 2406   * the allocated vmem_segs in the vmem arena which manages that part of kas.
2407 2407   * Currently, we do this for:
2408 2408   *
2409 2409   *      SEG             VMEM ARENA
2410 2410   *      kvseg           heap_arena
2411 2411   *      kvseg32         heap32_arena
2412 2412   *      kvseg_core      heap_core_arena
2413 2413   *
2414 2414   * In addition, we skip the segkpm segment in its entirety, since it is very
2415 2415   * sparse, and contains no new kernel data.
2416 2416   */
2417 2417  typedef struct kgrep_walk_data {
2418 2418          kgrep_cb_func *kg_cb;
2419 2419          void *kg_cbdata;
2420 2420          uintptr_t kg_kvseg;
2421 2421          uintptr_t kg_kvseg32;
2422 2422          uintptr_t kg_kvseg_core;
2423 2423          uintptr_t kg_segkpm;
2424 2424          uintptr_t kg_heap_lp_base;
2425 2425          uintptr_t kg_heap_lp_end;
2426 2426  } kgrep_walk_data_t;
2427 2427  
2428 2428  static int
2429 2429  kgrep_walk_seg(uintptr_t addr, const struct seg *seg, kgrep_walk_data_t *kg)
2430 2430  {
2431 2431          uintptr_t base = (uintptr_t)seg->s_base;
2432 2432  
2433 2433          if (addr == kg->kg_kvseg || addr == kg->kg_kvseg32 ||
2434 2434              addr == kg->kg_kvseg_core)
2435 2435                  return (WALK_NEXT);
2436 2436  
2437 2437          if ((uintptr_t)seg->s_ops == kg->kg_segkpm)
2438 2438                  return (WALK_NEXT);
2439 2439  
2440 2440          return (kg->kg_cb(base, base + seg->s_size, kg->kg_cbdata));
2441 2441  }
2442 2442  
2443 2443  /*ARGSUSED*/
2444 2444  static int
2445 2445  kgrep_walk_vseg(uintptr_t addr, const vmem_seg_t *seg, kgrep_walk_data_t *kg)
2446 2446  {
2447 2447          /*
2448 2448           * skip large page heap address range - it is scanned by walking
2449 2449           * allocated vmem_segs in the heap_lp_arena
2450 2450           */
2451 2451          if (seg->vs_start == kg->kg_heap_lp_base &&
2452 2452              seg->vs_end == kg->kg_heap_lp_end)
2453 2453                  return (WALK_NEXT);
2454 2454  
2455 2455          return (kg->kg_cb(seg->vs_start, seg->vs_end, kg->kg_cbdata));
2456 2456  }
2457 2457  
2458 2458  /*ARGSUSED*/
2459 2459  static int
2460 2460  kgrep_xwalk_vseg(uintptr_t addr, const vmem_seg_t *seg, kgrep_walk_data_t *kg)
2461 2461  {
2462 2462          return (kg->kg_cb(seg->vs_start, seg->vs_end, kg->kg_cbdata));
2463 2463  }
2464 2464  
2465 2465  static int
2466 2466  kgrep_walk_vmem(uintptr_t addr, const vmem_t *vmem, kgrep_walk_data_t *kg)
2467 2467  {
2468 2468          mdb_walk_cb_t walk_vseg = (mdb_walk_cb_t)kgrep_walk_vseg;
2469 2469  
2470 2470          if (strcmp(vmem->vm_name, "heap") != 0 &&
2471 2471              strcmp(vmem->vm_name, "heap32") != 0 &&
2472 2472              strcmp(vmem->vm_name, "heap_core") != 0 &&
2473 2473              strcmp(vmem->vm_name, "heap_lp") != 0)
2474 2474                  return (WALK_NEXT);
2475 2475  
2476 2476          if (strcmp(vmem->vm_name, "heap_lp") == 0)
2477 2477                  walk_vseg = (mdb_walk_cb_t)kgrep_xwalk_vseg;
2478 2478  
2479 2479          if (mdb_pwalk("vmem_alloc", walk_vseg, kg, addr) == -1) {
2480 2480                  mdb_warn("couldn't walk vmem_alloc for vmem %p", addr);
2481 2481                  return (WALK_ERR);
2482 2482          }
2483 2483  
2484 2484          return (WALK_NEXT);
2485 2485  }
2486 2486  
2487 2487  int
2488 2488  kgrep_subr(kgrep_cb_func *cb, void *cbdata)
2489 2489  {
2490 2490          GElf_Sym kas, kvseg, kvseg32, kvseg_core, segkpm;
2491 2491          kgrep_walk_data_t kg;
2492 2492  
2493 2493          if (mdb_get_state() == MDB_STATE_RUNNING) {
2494 2494                  mdb_warn("kgrep can only be run on a system "
2495 2495                      "dump or under kmdb; see dumpadm(1M)\n");
2496 2496                  return (DCMD_ERR);
2497 2497          }
2498 2498  
2499 2499          if (mdb_lookup_by_name("kas", &kas) == -1) {
2500 2500                  mdb_warn("failed to locate 'kas' symbol\n");
2501 2501                  return (DCMD_ERR);
2502 2502          }
2503 2503  
2504 2504          if (mdb_lookup_by_name("kvseg", &kvseg) == -1) {
2505 2505                  mdb_warn("failed to locate 'kvseg' symbol\n");
2506 2506                  return (DCMD_ERR);
2507 2507          }
2508 2508  
2509 2509          if (mdb_lookup_by_name("kvseg32", &kvseg32) == -1) {
2510 2510                  mdb_warn("failed to locate 'kvseg32' symbol\n");
2511 2511                  return (DCMD_ERR);
2512 2512          }
2513 2513  
2514 2514          if (mdb_lookup_by_name("kvseg_core", &kvseg_core) == -1) {
2515 2515                  mdb_warn("failed to locate 'kvseg_core' symbol\n");
2516 2516                  return (DCMD_ERR);
2517 2517          }
2518 2518  
2519 2519          if (mdb_lookup_by_name("segkpm_ops", &segkpm) == -1) {
2520 2520                  mdb_warn("failed to locate 'segkpm_ops' symbol\n");
2521 2521                  return (DCMD_ERR);
2522 2522          }
2523 2523  
2524 2524          if (mdb_readvar(&kg.kg_heap_lp_base, "heap_lp_base") == -1) {
2525 2525                  mdb_warn("failed to read 'heap_lp_base'\n");
2526 2526                  return (DCMD_ERR);
2527 2527          }
2528 2528  
2529 2529          if (mdb_readvar(&kg.kg_heap_lp_end, "heap_lp_end") == -1) {
2530 2530                  mdb_warn("failed to read 'heap_lp_end'\n");
2531 2531                  return (DCMD_ERR);
2532 2532          }
2533 2533  
2534 2534          kg.kg_cb = cb;
2535 2535          kg.kg_cbdata = cbdata;
2536 2536          kg.kg_kvseg = (uintptr_t)kvseg.st_value;
2537 2537          kg.kg_kvseg32 = (uintptr_t)kvseg32.st_value;
2538 2538          kg.kg_kvseg_core = (uintptr_t)kvseg_core.st_value;
2539 2539          kg.kg_segkpm = (uintptr_t)segkpm.st_value;
2540 2540  
2541 2541          if (mdb_pwalk("seg", (mdb_walk_cb_t)kgrep_walk_seg,
2542 2542              &kg, kas.st_value) == -1) {
2543 2543                  mdb_warn("failed to walk kas segments");
2544 2544                  return (DCMD_ERR);
2545 2545          }
2546 2546  
2547 2547          if (mdb_walk("vmem", (mdb_walk_cb_t)kgrep_walk_vmem, &kg) == -1) {
2548 2548                  mdb_warn("failed to walk heap/heap32 vmem arenas");
2549 2549                  return (DCMD_ERR);
2550 2550          }
2551 2551  
2552 2552          return (DCMD_OK);
2553 2553  }
2554 2554  
2555 2555  size_t
2556 2556  kgrep_subr_pagesize(void)
2557 2557  {
2558 2558          return (PAGESIZE);
2559 2559  }
2560 2560  
2561 2561  typedef struct file_walk_data {
2562 2562          struct uf_entry *fw_flist;
2563 2563          int fw_flistsz;
2564 2564          int fw_ndx;
2565 2565          int fw_nofiles;
2566 2566  } file_walk_data_t;
2567 2567  
2568 2568  typedef struct mdb_file_proc {
2569 2569          struct {
2570 2570                  struct {
2571 2571                          int                     fi_nfiles;
2572 2572                          uf_entry_t *volatile    fi_list;
2573 2573                  } u_finfo;
2574 2574          } p_user;
2575 2575  } mdb_file_proc_t;
2576 2576  
2577 2577  int
2578 2578  file_walk_init(mdb_walk_state_t *wsp)
2579 2579  {
2580 2580          file_walk_data_t *fw;
2581 2581          mdb_file_proc_t p;
2582 2582  
2583 2583          if (wsp->walk_addr == 0) {
2584 2584                  mdb_warn("file walk doesn't support global walks\n");
2585 2585                  return (WALK_ERR);
2586 2586          }
2587 2587  
2588 2588          fw = mdb_alloc(sizeof (file_walk_data_t), UM_SLEEP);
2589 2589  
2590 2590          if (mdb_ctf_vread(&p, "proc_t", "mdb_file_proc_t",
2591 2591              wsp->walk_addr, 0) == -1) {
2592 2592                  mdb_free(fw, sizeof (file_walk_data_t));
2593 2593                  mdb_warn("failed to read proc structure at %p", wsp->walk_addr);
2594 2594                  return (WALK_ERR);
2595 2595          }
2596 2596  
2597 2597          if (p.p_user.u_finfo.fi_nfiles == 0) {
2598 2598                  mdb_free(fw, sizeof (file_walk_data_t));
2599 2599                  return (WALK_DONE);
2600 2600          }
2601 2601  
2602 2602          fw->fw_nofiles = p.p_user.u_finfo.fi_nfiles;
2603 2603          fw->fw_flistsz = sizeof (struct uf_entry) * fw->fw_nofiles;
2604 2604          fw->fw_flist = mdb_alloc(fw->fw_flistsz, UM_SLEEP);
2605 2605  
2606 2606          if (mdb_vread(fw->fw_flist, fw->fw_flistsz,
2607 2607              (uintptr_t)p.p_user.u_finfo.fi_list) == -1) {
2608 2608                  mdb_warn("failed to read file array at %p",
2609 2609                      p.p_user.u_finfo.fi_list);
2610 2610                  mdb_free(fw->fw_flist, fw->fw_flistsz);
2611 2611                  mdb_free(fw, sizeof (file_walk_data_t));
2612 2612                  return (WALK_ERR);
2613 2613          }
2614 2614  
2615 2615          fw->fw_ndx = 0;
2616 2616          wsp->walk_data = fw;
2617 2617  
2618 2618          return (WALK_NEXT);
2619 2619  }
2620 2620  
2621 2621  int
2622 2622  file_walk_step(mdb_walk_state_t *wsp)
2623 2623  {
2624 2624          file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data;
2625 2625          struct file file;
2626 2626          uintptr_t fp;
2627 2627  
2628 2628  again:
2629 2629          if (fw->fw_ndx == fw->fw_nofiles)
2630 2630                  return (WALK_DONE);
2631 2631  
2632 2632          if ((fp = (uintptr_t)fw->fw_flist[fw->fw_ndx++].uf_file) == 0)
2633 2633                  goto again;
2634 2634  
2635 2635          (void) mdb_vread(&file, sizeof (file), (uintptr_t)fp);
2636 2636          return (wsp->walk_callback(fp, &file, wsp->walk_cbdata));
2637 2637  }
2638 2638  
2639 2639  int
2640 2640  allfile_walk_step(mdb_walk_state_t *wsp)
2641 2641  {
2642 2642          file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data;
2643 2643          struct file file;
2644 2644          uintptr_t fp;
2645 2645  
2646 2646          if (fw->fw_ndx == fw->fw_nofiles)
2647 2647                  return (WALK_DONE);
2648 2648  
2649 2649          if ((fp = (uintptr_t)fw->fw_flist[fw->fw_ndx++].uf_file) != 0)
2650 2650                  (void) mdb_vread(&file, sizeof (file), (uintptr_t)fp);
2651 2651          else
2652 2652                  bzero(&file, sizeof (file));
2653 2653  
2654 2654          return (wsp->walk_callback(fp, &file, wsp->walk_cbdata));
2655 2655  }
2656 2656  
2657 2657  void
2658 2658  file_walk_fini(mdb_walk_state_t *wsp)
2659 2659  {
2660 2660          file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data;
2661 2661  
2662 2662          mdb_free(fw->fw_flist, fw->fw_flistsz);
2663 2663          mdb_free(fw, sizeof (file_walk_data_t));
2664 2664  }
2665 2665  
2666 2666  int
2667 2667  port_walk_init(mdb_walk_state_t *wsp)
2668 2668  {
2669 2669          if (wsp->walk_addr == 0) {
2670 2670                  mdb_warn("port walk doesn't support global walks\n");
2671 2671                  return (WALK_ERR);
2672 2672          }
2673 2673  
2674 2674          if (mdb_layered_walk("file", wsp) == -1) {
2675 2675                  mdb_warn("couldn't walk 'file'");
2676 2676                  return (WALK_ERR);
2677 2677          }
2678 2678          return (WALK_NEXT);
2679 2679  }
2680 2680  
2681 2681  int
2682 2682  port_walk_step(mdb_walk_state_t *wsp)
2683 2683  {
2684 2684          struct vnode    vn;
2685 2685          uintptr_t       vp;
2686 2686          uintptr_t       pp;
2687 2687          struct port     port;
2688 2688  
2689 2689          vp = (uintptr_t)((struct file *)wsp->walk_layer)->f_vnode;
2690 2690          if (mdb_vread(&vn, sizeof (vn), vp) == -1) {
2691 2691                  mdb_warn("failed to read vnode_t at %p", vp);
2692 2692                  return (WALK_ERR);
2693 2693          }
2694 2694          if (vn.v_type != VPORT)
2695 2695                  return (WALK_NEXT);
2696 2696  
2697 2697          pp = (uintptr_t)vn.v_data;
2698 2698          if (mdb_vread(&port, sizeof (port), pp) == -1) {
2699 2699                  mdb_warn("failed to read port_t at %p", pp);
2700 2700                  return (WALK_ERR);
2701 2701          }
2702 2702          return (wsp->walk_callback(pp, &port, wsp->walk_cbdata));
2703 2703  }
2704 2704  
2705 2705  typedef struct portev_walk_data {
2706 2706          list_node_t     *pev_node;
2707 2707          list_node_t     *pev_last;
2708 2708          size_t          pev_offset;
2709 2709  } portev_walk_data_t;
2710 2710  
2711 2711  int
2712 2712  portev_walk_init(mdb_walk_state_t *wsp)
2713 2713  {
2714 2714          portev_walk_data_t *pevd;
2715 2715          struct port     port;
2716 2716          struct vnode    vn;
2717 2717          struct list     *list;
2718 2718          uintptr_t       vp;
2719 2719  
2720 2720          if (wsp->walk_addr == 0) {
2721 2721                  mdb_warn("portev walk doesn't support global walks\n");
2722 2722                  return (WALK_ERR);
2723 2723          }
2724 2724  
2725 2725          pevd = mdb_alloc(sizeof (portev_walk_data_t), UM_SLEEP);
2726 2726  
2727 2727          if (mdb_vread(&port, sizeof (port), wsp->walk_addr) == -1) {
2728 2728                  mdb_free(pevd, sizeof (portev_walk_data_t));
2729 2729                  mdb_warn("failed to read port structure at %p", wsp->walk_addr);
2730 2730                  return (WALK_ERR);
2731 2731          }
2732 2732  
2733 2733          vp = (uintptr_t)port.port_vnode;
2734 2734          if (mdb_vread(&vn, sizeof (vn), vp) == -1) {
2735 2735                  mdb_free(pevd, sizeof (portev_walk_data_t));
2736 2736                  mdb_warn("failed to read vnode_t at %p", vp);
2737 2737                  return (WALK_ERR);
2738 2738          }
2739 2739  
2740 2740          if (vn.v_type != VPORT) {
2741 2741                  mdb_free(pevd, sizeof (portev_walk_data_t));
2742 2742                  mdb_warn("input address (%p) does not point to an event port",
2743 2743                      wsp->walk_addr);
2744 2744                  return (WALK_ERR);
2745 2745          }
2746 2746  
2747 2747          if (port.port_queue.portq_nent == 0) {
2748 2748                  mdb_free(pevd, sizeof (portev_walk_data_t));
2749 2749                  return (WALK_DONE);
2750 2750          }
2751 2751          list = &port.port_queue.portq_list;
2752 2752          pevd->pev_offset = list->list_offset;
2753 2753          pevd->pev_last = list->list_head.list_prev;
2754 2754          pevd->pev_node = list->list_head.list_next;
2755 2755          wsp->walk_data = pevd;
2756 2756          return (WALK_NEXT);
2757 2757  }
2758 2758  
2759 2759  int
2760 2760  portev_walk_step(mdb_walk_state_t *wsp)
2761 2761  {
2762 2762          portev_walk_data_t      *pevd;
2763 2763          struct port_kevent      ev;
2764 2764          uintptr_t               evp;
2765 2765  
2766 2766          pevd = (portev_walk_data_t *)wsp->walk_data;
2767 2767  
2768 2768          if (pevd->pev_last == NULL)
2769 2769                  return (WALK_DONE);
2770 2770          if (pevd->pev_node == pevd->pev_last)
2771 2771                  pevd->pev_last = NULL;          /* last round */
2772 2772  
2773 2773          evp = ((uintptr_t)(((char *)pevd->pev_node) - pevd->pev_offset));
2774 2774          if (mdb_vread(&ev, sizeof (ev), evp) == -1) {
2775 2775                  mdb_warn("failed to read port_kevent at %p", evp);
2776 2776                  return (WALK_DONE);
2777 2777          }
2778 2778          pevd->pev_node = ev.portkev_node.list_next;
2779 2779          return (wsp->walk_callback(evp, &ev, wsp->walk_cbdata));
2780 2780  }
2781 2781  
2782 2782  void
2783 2783  portev_walk_fini(mdb_walk_state_t *wsp)
2784 2784  {
2785 2785          portev_walk_data_t *pevd = (portev_walk_data_t *)wsp->walk_data;
2786 2786  
2787 2787          if (pevd != NULL)
2788 2788                  mdb_free(pevd, sizeof (portev_walk_data_t));
2789 2789  }
2790 2790  
2791 2791  typedef struct proc_walk_data {
2792 2792          uintptr_t *pw_stack;
2793 2793          int pw_depth;
2794 2794          int pw_max;
2795 2795  } proc_walk_data_t;
2796 2796  
2797 2797  int
2798 2798  proc_walk_init(mdb_walk_state_t *wsp)
2799 2799  {
2800 2800          GElf_Sym sym;
2801 2801          proc_walk_data_t *pw;
2802 2802  
2803 2803          if (wsp->walk_addr == 0) {
2804 2804                  if (mdb_lookup_by_name("p0", &sym) == -1) {
2805 2805                          mdb_warn("failed to read 'practive'");
2806 2806                          return (WALK_ERR);
2807 2807                  }
2808 2808                  wsp->walk_addr = (uintptr_t)sym.st_value;
2809 2809          }
2810 2810  
2811 2811          pw = mdb_zalloc(sizeof (proc_walk_data_t), UM_SLEEP);
2812 2812  
2813 2813          if (mdb_readvar(&pw->pw_max, "nproc") == -1) {
2814 2814                  mdb_warn("failed to read 'nproc'");
2815 2815                  mdb_free(pw, sizeof (pw));
2816 2816                  return (WALK_ERR);
2817 2817          }
2818 2818  
2819 2819          pw->pw_stack = mdb_alloc(pw->pw_max * sizeof (uintptr_t), UM_SLEEP);
2820 2820          wsp->walk_data = pw;
2821 2821  
2822 2822          return (WALK_NEXT);
2823 2823  }
2824 2824  
2825 2825  typedef struct mdb_walk_proc {
2826 2826          struct proc     *p_child;
2827 2827          struct proc     *p_sibling;
2828 2828  } mdb_walk_proc_t;
2829 2829  
2830 2830  int
2831 2831  proc_walk_step(mdb_walk_state_t *wsp)
2832 2832  {
2833 2833          proc_walk_data_t *pw = wsp->walk_data;
2834 2834          uintptr_t addr = wsp->walk_addr;
2835 2835          uintptr_t cld, sib;
2836 2836          int status;
2837 2837          mdb_walk_proc_t pr;
2838 2838  
2839 2839          if (mdb_ctf_vread(&pr, "proc_t", "mdb_walk_proc_t",
2840 2840              addr, 0) == -1) {
2841 2841                  mdb_warn("failed to read proc at %p", addr);
2842 2842                  return (WALK_DONE);
2843 2843          }
2844 2844  
2845 2845          cld = (uintptr_t)pr.p_child;
2846 2846          sib = (uintptr_t)pr.p_sibling;
2847 2847  
2848 2848          if (pw->pw_depth > 0 && addr == pw->pw_stack[pw->pw_depth - 1]) {
2849 2849                  pw->pw_depth--;
2850 2850                  goto sib;
2851 2851          }
2852 2852  
2853 2853          /*
2854 2854           * Always pass NULL as the local copy pointer. Consumers
2855 2855           * should use mdb_ctf_vread() to read their own minimal
2856 2856           * version of proc_t. Thus minimizing the chance of breakage
2857 2857           * with older crash dumps.
2858 2858           */
2859 2859          status = wsp->walk_callback(addr, NULL, wsp->walk_cbdata);
2860 2860  
2861 2861          if (status != WALK_NEXT)
2862 2862                  return (status);
2863 2863  
2864 2864          if ((wsp->walk_addr = cld) != 0) {
2865 2865                  if (mdb_ctf_vread(&pr, "proc_t", "mdb_walk_proc_t",
2866 2866                      cld, 0) == -1) {
2867 2867                          mdb_warn("proc %p has invalid p_child %p; skipping\n",
2868 2868                              addr, cld);
2869 2869                          goto sib;
2870 2870                  }
2871 2871  
2872 2872                  pw->pw_stack[pw->pw_depth++] = addr;
2873 2873  
2874 2874                  if (pw->pw_depth == pw->pw_max) {
2875 2875                          mdb_warn("depth %d exceeds max depth; try again\n",
2876 2876                              pw->pw_depth);
2877 2877                          return (WALK_DONE);
2878 2878                  }
2879 2879                  return (WALK_NEXT);
2880 2880          }
2881 2881  
2882 2882  sib:
2883 2883          /*
2884 2884           * We know that p0 has no siblings, and if another starting proc
2885 2885           * was given, we don't want to walk its siblings anyway.
2886 2886           */
2887 2887          if (pw->pw_depth == 0)
2888 2888                  return (WALK_DONE);
2889 2889  
2890 2890          if (sib != 0 && mdb_ctf_vread(&pr, "proc_t", "mdb_walk_proc_t",
2891 2891              sib, 0) == -1) {
2892 2892                  mdb_warn("proc %p has invalid p_sibling %p; skipping\n",
2893 2893                      addr, sib);
2894 2894                  sib = 0;
2895 2895          }
2896 2896  
2897 2897          if ((wsp->walk_addr = sib) == 0) {
2898 2898                  if (pw->pw_depth > 0) {
2899 2899                          wsp->walk_addr = pw->pw_stack[pw->pw_depth - 1];
2900 2900                          return (WALK_NEXT);
2901 2901                  }
2902 2902                  return (WALK_DONE);
2903 2903          }
2904 2904  
2905 2905          return (WALK_NEXT);
2906 2906  }
2907 2907  
2908 2908  void
2909 2909  proc_walk_fini(mdb_walk_state_t *wsp)
2910 2910  {
2911 2911          proc_walk_data_t *pw = wsp->walk_data;
2912 2912  
2913 2913          mdb_free(pw->pw_stack, pw->pw_max * sizeof (uintptr_t));
2914 2914          mdb_free(pw, sizeof (proc_walk_data_t));
2915 2915  }
2916 2916  
2917 2917  int
2918 2918  task_walk_init(mdb_walk_state_t *wsp)
2919 2919  {
2920 2920          task_t task;
2921 2921  
2922 2922          if (mdb_vread(&task, sizeof (task_t), wsp->walk_addr) == -1) {
2923 2923                  mdb_warn("failed to read task at %p", wsp->walk_addr);
2924 2924                  return (WALK_ERR);
2925 2925          }
2926 2926          wsp->walk_addr = (uintptr_t)task.tk_memb_list;
2927 2927          wsp->walk_data = task.tk_memb_list;
2928 2928          return (WALK_NEXT);
2929 2929  }
2930 2930  
2931 2931  typedef struct mdb_task_proc {
2932 2932          struct proc     *p_tasknext;
2933 2933  } mdb_task_proc_t;
2934 2934  
2935 2935  int
2936 2936  task_walk_step(mdb_walk_state_t *wsp)
2937 2937  {
2938 2938          mdb_task_proc_t proc;
2939 2939          int status;
2940 2940  
2941 2941          if (mdb_ctf_vread(&proc, "proc_t", "mdb_task_proc_t",
2942 2942              wsp->walk_addr, 0) == -1) {
2943 2943                  mdb_warn("failed to read proc at %p", wsp->walk_addr);
2944 2944                  return (WALK_DONE);
2945 2945          }
2946 2946  
2947 2947          status = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata);
2948 2948  
2949 2949          if (proc.p_tasknext == wsp->walk_data)
2950 2950                  return (WALK_DONE);
2951 2951  
2952 2952          wsp->walk_addr = (uintptr_t)proc.p_tasknext;
2953 2953          return (status);
2954 2954  }
2955 2955  
2956 2956  int
2957 2957  project_walk_init(mdb_walk_state_t *wsp)
2958 2958  {
2959 2959          if (wsp->walk_addr == 0) {
2960 2960                  if (mdb_readvar(&wsp->walk_addr, "proj0p") == -1) {
2961 2961                          mdb_warn("failed to read 'proj0p'");
2962 2962                          return (WALK_ERR);
2963 2963                  }
2964 2964          }
2965 2965          wsp->walk_data = (void *)wsp->walk_addr;
2966 2966          return (WALK_NEXT);
2967 2967  }
2968 2968  
2969 2969  int
2970 2970  project_walk_step(mdb_walk_state_t *wsp)
2971 2971  {
2972 2972          uintptr_t addr = wsp->walk_addr;
2973 2973          kproject_t pj;
2974 2974          int status;
2975 2975  
2976 2976          if (mdb_vread(&pj, sizeof (kproject_t), addr) == -1) {
2977 2977                  mdb_warn("failed to read project at %p", addr);
2978 2978                  return (WALK_DONE);
2979 2979          }
2980 2980          status = wsp->walk_callback(addr, &pj, wsp->walk_cbdata);
2981 2981          if (status != WALK_NEXT)
2982 2982                  return (status);
2983 2983          wsp->walk_addr = (uintptr_t)pj.kpj_next;
2984 2984          if ((void *)wsp->walk_addr == wsp->walk_data)
2985 2985                  return (WALK_DONE);
2986 2986          return (WALK_NEXT);
2987 2987  }
2988 2988  
2989 2989  static int
2990 2990  generic_walk_step(mdb_walk_state_t *wsp)
2991 2991  {
2992 2992          return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
2993 2993              wsp->walk_cbdata));
2994 2994  }
2995 2995  
2996 2996  static int
2997 2997  cpu_walk_cmp(const void *l, const void *r)
2998 2998  {
2999 2999          uintptr_t lhs = *((uintptr_t *)l);
3000 3000          uintptr_t rhs = *((uintptr_t *)r);
3001 3001          cpu_t lcpu, rcpu;
3002 3002  
3003 3003          (void) mdb_vread(&lcpu, sizeof (lcpu), lhs);
3004 3004          (void) mdb_vread(&rcpu, sizeof (rcpu), rhs);
3005 3005  
3006 3006          if (lcpu.cpu_id < rcpu.cpu_id)
3007 3007                  return (-1);
3008 3008  
3009 3009          if (lcpu.cpu_id > rcpu.cpu_id)
3010 3010                  return (1);
3011 3011  
3012 3012          return (0);
3013 3013  }
3014 3014  
3015 3015  typedef struct cpu_walk {
3016 3016          uintptr_t *cw_array;
3017 3017          int cw_ndx;
3018 3018  } cpu_walk_t;
3019 3019  
3020 3020  int
3021 3021  cpu_walk_init(mdb_walk_state_t *wsp)
3022 3022  {
3023 3023          cpu_walk_t *cw;
3024 3024          int max_ncpus, i = 0;
3025 3025          uintptr_t current, first;
3026 3026          cpu_t cpu, panic_cpu;
3027 3027          uintptr_t panicstr, addr;
3028 3028          GElf_Sym sym;
3029 3029  
3030 3030          cw = mdb_zalloc(sizeof (cpu_walk_t), UM_SLEEP | UM_GC);
3031 3031  
3032 3032          if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) {
3033 3033                  mdb_warn("failed to read 'max_ncpus'");
3034 3034                  return (WALK_ERR);
3035 3035          }
3036 3036  
3037 3037          if (mdb_readvar(&panicstr, "panicstr") == -1) {
3038 3038                  mdb_warn("failed to read 'panicstr'");
3039 3039                  return (WALK_ERR);
3040 3040          }
3041 3041  
3042 3042          if (panicstr != 0) {
3043 3043                  if (mdb_lookup_by_name("panic_cpu", &sym) == -1) {
3044 3044                          mdb_warn("failed to find 'panic_cpu'");
3045 3045                          return (WALK_ERR);
3046 3046                  }
3047 3047  
3048 3048                  addr = (uintptr_t)sym.st_value;
3049 3049  
3050 3050                  if (mdb_vread(&panic_cpu, sizeof (cpu_t), addr) == -1) {
3051 3051                          mdb_warn("failed to read 'panic_cpu'");
3052 3052                          return (WALK_ERR);
3053 3053                  }
3054 3054          }
3055 3055  
3056 3056          /*
3057 3057           * Unfortunately, there is no platform-independent way to walk
3058 3058           * CPUs in ID order.  We therefore loop through in cpu_next order,
3059 3059           * building an array of CPU pointers which will subsequently be
3060 3060           * sorted.
3061 3061           */
3062 3062          cw->cw_array =
3063 3063              mdb_zalloc((max_ncpus + 1) * sizeof (uintptr_t), UM_SLEEP | UM_GC);
3064 3064  
3065 3065          if (mdb_readvar(&first, "cpu_list") == -1) {
3066 3066                  mdb_warn("failed to read 'cpu_list'");
3067 3067                  return (WALK_ERR);
3068 3068          }
3069 3069  
3070 3070          current = first;
3071 3071          do {
3072 3072                  if (mdb_vread(&cpu, sizeof (cpu), current) == -1) {
3073 3073                          mdb_warn("failed to read cpu at %p", current);
3074 3074                          return (WALK_ERR);
3075 3075                  }
3076 3076  
3077 3077                  if (panicstr != 0 && panic_cpu.cpu_id == cpu.cpu_id) {
3078 3078                          cw->cw_array[i++] = addr;
3079 3079                  } else {
3080 3080                          cw->cw_array[i++] = current;
3081 3081                  }
3082 3082          } while ((current = (uintptr_t)cpu.cpu_next) != first);
3083 3083  
3084 3084          qsort(cw->cw_array, i, sizeof (uintptr_t), cpu_walk_cmp);
3085 3085          wsp->walk_data = cw;
3086 3086  
3087 3087          return (WALK_NEXT);
3088 3088  }
3089 3089  
3090 3090  int
3091 3091  cpu_walk_step(mdb_walk_state_t *wsp)
3092 3092  {
3093 3093          cpu_walk_t *cw = wsp->walk_data;
3094 3094          cpu_t cpu;
3095 3095          uintptr_t addr = cw->cw_array[cw->cw_ndx++];
3096 3096  
3097 3097          if (addr == 0)
3098 3098                  return (WALK_DONE);
3099 3099  
3100 3100          if (mdb_vread(&cpu, sizeof (cpu), addr) == -1) {
3101 3101                  mdb_warn("failed to read cpu at %p", addr);
3102 3102                  return (WALK_DONE);
3103 3103          }
3104 3104  
3105 3105          return (wsp->walk_callback(addr, &cpu, wsp->walk_cbdata));
3106 3106  }
3107 3107  
3108 3108  typedef struct cpuinfo_data {
3109 3109          intptr_t cid_cpu;
3110 3110          uintptr_t **cid_ithr;
3111 3111          char    cid_print_head;
3112 3112          char    cid_print_thr;
3113 3113          char    cid_print_ithr;
3114 3114          char    cid_print_flags;
3115 3115  } cpuinfo_data_t;
3116 3116  
3117 3117  int
3118 3118  cpuinfo_walk_ithread(uintptr_t addr, const kthread_t *thr, cpuinfo_data_t *cid)
3119 3119  {
3120 3120          cpu_t c;
3121 3121          int id;
3122 3122          uint8_t pil;
3123 3123  
3124 3124          if (!(thr->t_flag & T_INTR_THREAD) || thr->t_state == TS_FREE)
3125 3125                  return (WALK_NEXT);
3126 3126  
3127 3127          if (thr->t_bound_cpu == NULL) {
3128 3128                  mdb_warn("thr %p is intr thread w/out a CPU\n", addr);
3129 3129                  return (WALK_NEXT);
3130 3130          }
3131 3131  
3132 3132          (void) mdb_vread(&c, sizeof (c), (uintptr_t)thr->t_bound_cpu);
3133 3133  
3134 3134          if ((id = c.cpu_id) >= NCPU) {
3135 3135                  mdb_warn("CPU %p has id (%d) greater than NCPU (%d)\n",
3136 3136                      thr->t_bound_cpu, id, NCPU);
3137 3137                  return (WALK_NEXT);
3138 3138          }
3139 3139  
3140 3140          if ((pil = thr->t_pil) >= NINTR) {
3141 3141                  mdb_warn("thread %p has pil (%d) greater than %d\n",
3142 3142                      addr, pil, NINTR);
3143 3143                  return (WALK_NEXT);
3144 3144          }
3145 3145  
3146 3146          if (cid->cid_ithr[id][pil] != 0) {
3147 3147                  mdb_warn("CPU %d has multiple threads at pil %d (at least "
3148 3148                      "%p and %p)\n", id, pil, addr, cid->cid_ithr[id][pil]);
3149 3149                  return (WALK_NEXT);
3150 3150          }
3151 3151  
3152 3152          cid->cid_ithr[id][pil] = addr;
3153 3153  
3154 3154          return (WALK_NEXT);
3155 3155  }
3156 3156  
3157 3157  #define CPUINFO_IDWIDTH         3
3158 3158  #define CPUINFO_FLAGWIDTH       9
3159 3159  
3160 3160  #ifdef _LP64
3161 3161  #if defined(__amd64)
3162 3162  #define CPUINFO_TWIDTH          16
3163 3163  #define CPUINFO_CPUWIDTH        16
3164 3164  #else
3165 3165  #define CPUINFO_CPUWIDTH        11
3166 3166  #define CPUINFO_TWIDTH          11
3167 3167  #endif
3168 3168  #else
3169 3169  #define CPUINFO_CPUWIDTH        8
3170 3170  #define CPUINFO_TWIDTH          8
3171 3171  #endif
3172 3172  
3173 3173  #define CPUINFO_THRDELT         (CPUINFO_IDWIDTH + CPUINFO_CPUWIDTH + 9)
3174 3174  #define CPUINFO_FLAGDELT        (CPUINFO_IDWIDTH + CPUINFO_CPUWIDTH + 4)
3175 3175  #define CPUINFO_ITHRDELT        4
3176 3176  
3177 3177  #define CPUINFO_INDENT  mdb_printf("%*s", CPUINFO_THRDELT, \
3178 3178      flagline < nflaglines ? flagbuf[flagline++] : "")
3179 3179  
3180 3180  typedef struct mdb_cpuinfo_proc {
3181 3181          struct {
3182 3182                  char            u_comm[MAXCOMLEN + 1];
3183 3183          } p_user;
3184 3184  } mdb_cpuinfo_proc_t;
3185 3185  
3186 3186  int
3187 3187  cpuinfo_walk_cpu(uintptr_t addr, const cpu_t *cpu, cpuinfo_data_t *cid)
3188 3188  {
3189 3189          kthread_t t;
3190 3190          disp_t disp;
3191 3191          mdb_cpuinfo_proc_t p;
3192 3192          uintptr_t pinned;
3193 3193          char **flagbuf;
3194 3194          int nflaglines = 0, flagline = 0, bspl, rval = WALK_NEXT;
3195 3195  
3196 3196          const char *flags[] = {
3197 3197              "RUNNING", "READY", "QUIESCED", "EXISTS",
3198 3198              "ENABLE", "OFFLINE", "POWEROFF", "FROZEN",
3199 3199              "SPARE", "FAULTED", "DISABLED", NULL
3200 3200          };
3201 3201  
3202 3202          if (cid->cid_cpu != -1) {
3203 3203                  if (addr != cid->cid_cpu && cpu->cpu_id != cid->cid_cpu)
3204 3204                          return (WALK_NEXT);
3205 3205  
3206 3206                  /*
3207 3207                   * Set cid_cpu to -1 to indicate that we found a matching CPU.
3208 3208                   */
3209 3209                  cid->cid_cpu = -1;
3210 3210                  rval = WALK_DONE;
3211 3211          }
3212 3212  
3213 3213          if (cid->cid_print_head) {
3214 3214                  mdb_printf("%3s %-*s %3s %4s %4s %3s %4s %5s %-6s %-*s %s\n",
3215 3215                      "ID", CPUINFO_CPUWIDTH, "ADDR", "FLG", "NRUN", "BSPL",
3216 3216                      "PRI", "RNRN", "KRNRN", "SWITCH", CPUINFO_TWIDTH, "THREAD",
3217 3217                      "PROC");
3218 3218                  cid->cid_print_head = FALSE;
3219 3219          }
3220 3220  
3221 3221          bspl = cpu->cpu_base_spl;
3222 3222  
3223 3223          if (mdb_vread(&disp, sizeof (disp_t), (uintptr_t)cpu->cpu_disp) == -1) {
3224 3224                  mdb_warn("failed to read disp_t at %p", cpu->cpu_disp);
3225 3225                  return (WALK_ERR);
3226 3226          }
3227 3227  
3228 3228          mdb_printf("%3d %0*p %3x %4d %4d ",
3229 3229              cpu->cpu_id, CPUINFO_CPUWIDTH, addr, cpu->cpu_flags,
3230 3230              disp.disp_nrunnable, bspl);
3231 3231  
3232 3232          if (mdb_vread(&t, sizeof (t), (uintptr_t)cpu->cpu_thread) != -1) {
3233 3233                  mdb_printf("%3d ", t.t_pri);
3234 3234          } else {
3235 3235                  mdb_printf("%3s ", "-");
3236 3236          }
3237 3237  
3238 3238          mdb_printf("%4s %5s ", cpu->cpu_runrun ? "yes" : "no",
3239 3239              cpu->cpu_kprunrun ? "yes" : "no");
3240 3240  
3241 3241          if (cpu->cpu_last_swtch) {
3242 3242                  mdb_printf("t-%-4d ",
3243 3243                      (clock_t)mdb_get_lbolt() - cpu->cpu_last_swtch);
3244 3244          } else {
3245 3245                  mdb_printf("%-6s ", "-");
3246 3246          }
3247 3247  
3248 3248          mdb_printf("%0*p", CPUINFO_TWIDTH, cpu->cpu_thread);
3249 3249  
3250 3250          if (cpu->cpu_thread == cpu->cpu_idle_thread)
3251 3251                  mdb_printf(" (idle)\n");
3252 3252          else if (cpu->cpu_thread == NULL)
3253 3253                  mdb_printf(" -\n");
3254 3254          else {
3255 3255                  if (mdb_ctf_vread(&p, "proc_t", "mdb_cpuinfo_proc_t",
3256 3256                      (uintptr_t)t.t_procp, 0) != -1) {
3257 3257                          mdb_printf(" %s\n", p.p_user.u_comm);
3258 3258                  } else {
3259 3259                          mdb_printf(" ?\n");
3260 3260                  }
3261 3261          }
3262 3262  
3263 3263          flagbuf = mdb_zalloc(sizeof (flags), UM_SLEEP | UM_GC);
3264 3264  
3265 3265          if (cid->cid_print_flags) {
3266 3266                  int first = 1, i, j, k;
3267 3267                  char *s;
3268 3268  
3269 3269                  cid->cid_print_head = TRUE;
3270 3270  
3271 3271                  for (i = 1, j = 0; flags[j] != NULL; i <<= 1, j++) {
3272 3272                          if (!(cpu->cpu_flags & i))
3273 3273                                  continue;
3274 3274  
3275 3275                          if (first) {
3276 3276                                  s = mdb_alloc(CPUINFO_THRDELT + 1,
3277 3277                                      UM_GC | UM_SLEEP);
3278 3278  
3279 3279                                  (void) mdb_snprintf(s, CPUINFO_THRDELT + 1,
3280 3280                                      "%*s|%*s", CPUINFO_FLAGDELT, "",
3281 3281                                      CPUINFO_THRDELT - 1 - CPUINFO_FLAGDELT, "");
3282 3282                                  flagbuf[nflaglines++] = s;
3283 3283                          }
3284 3284  
3285 3285                          s = mdb_alloc(CPUINFO_THRDELT + 1, UM_GC | UM_SLEEP);
3286 3286                          (void) mdb_snprintf(s, CPUINFO_THRDELT + 1, "%*s%*s %s",
3287 3287                              CPUINFO_IDWIDTH + CPUINFO_CPUWIDTH -
3288 3288                              CPUINFO_FLAGWIDTH, "", CPUINFO_FLAGWIDTH, flags[j],
3289 3289                              first ? "<--+" : "");
3290 3290  
3291 3291                          for (k = strlen(s); k < CPUINFO_THRDELT; k++)
3292 3292                                  s[k] = ' ';
3293 3293                          s[k] = '\0';
3294 3294  
3295 3295                          flagbuf[nflaglines++] = s;
3296 3296                          first = 0;
3297 3297                  }
3298 3298          }
3299 3299  
3300 3300          if (cid->cid_print_ithr) {
3301 3301                  int i, found_one = FALSE;
3302 3302                  int print_thr = disp.disp_nrunnable && cid->cid_print_thr;
3303 3303  
3304 3304                  for (i = NINTR - 1; i >= 0; i--) {
3305 3305                          uintptr_t iaddr = cid->cid_ithr[cpu->cpu_id][i];
3306 3306  
3307 3307                          if (iaddr == 0)
3308 3308                                  continue;
3309 3309  
3310 3310                          if (!found_one) {
3311 3311                                  found_one = TRUE;
3312 3312  
3313 3313                                  CPUINFO_INDENT;
3314 3314                                  mdb_printf("%c%*s|\n", print_thr ? '|' : ' ',
3315 3315                                      CPUINFO_ITHRDELT, "");
3316 3316  
3317 3317                                  CPUINFO_INDENT;
3318 3318                                  mdb_printf("%c%*s+--> %3s %s\n",
3319 3319                                      print_thr ? '|' : ' ', CPUINFO_ITHRDELT,
3320 3320                                      "", "PIL", "THREAD");
3321 3321                          }
3322 3322  
3323 3323                          if (mdb_vread(&t, sizeof (t), iaddr) == -1) {
3324 3324                                  mdb_warn("failed to read kthread_t at %p",
3325 3325                                      iaddr);
3326 3326                                  return (WALK_ERR);
3327 3327                          }
3328 3328  
3329 3329                          CPUINFO_INDENT;
3330 3330                          mdb_printf("%c%*s     %3d %0*p\n",
3331 3331                              print_thr ? '|' : ' ', CPUINFO_ITHRDELT, "",
3332 3332                              t.t_pil, CPUINFO_TWIDTH, iaddr);
3333 3333  
3334 3334                          pinned = (uintptr_t)t.t_intr;
3335 3335                  }
3336 3336  
3337 3337                  if (found_one && pinned != 0) {
3338 3338                          cid->cid_print_head = TRUE;
3339 3339                          (void) strcpy(p.p_user.u_comm, "?");
3340 3340  
3341 3341                          if (mdb_vread(&t, sizeof (t),
3342 3342                              (uintptr_t)pinned) == -1) {
3343 3343                                  mdb_warn("failed to read kthread_t at %p",
3344 3344                                      pinned);
3345 3345                                  return (WALK_ERR);
3346 3346                          }
3347 3347                          if (mdb_ctf_vread(&p, "proc_t", "mdb_cpuinfo_proc_t",
3348 3348                              (uintptr_t)t.t_procp, 0) == -1) {
3349 3349                                  mdb_warn("failed to read proc_t at %p",
3350 3350                                      t.t_procp);
3351 3351                                  return (WALK_ERR);
3352 3352                          }
3353 3353  
3354 3354                          CPUINFO_INDENT;
3355 3355                          mdb_printf("%c%*s     %3s %0*p %s\n",
3356 3356                              print_thr ? '|' : ' ', CPUINFO_ITHRDELT, "", "-",
3357 3357                              CPUINFO_TWIDTH, pinned,
3358 3358                              pinned == (uintptr_t)cpu->cpu_idle_thread ?
3359 3359                              "(idle)" : p.p_user.u_comm);
3360 3360                  }
3361 3361          }
3362 3362  
3363 3363          if (disp.disp_nrunnable && cid->cid_print_thr) {
3364 3364                  dispq_t *dq;
3365 3365  
3366 3366                  int i, npri = disp.disp_npri;
3367 3367  
3368 3368                  dq = mdb_alloc(sizeof (dispq_t) * npri, UM_SLEEP | UM_GC);
3369 3369  
3370 3370                  if (mdb_vread(dq, sizeof (dispq_t) * npri,
3371 3371                      (uintptr_t)disp.disp_q) == -1) {
3372 3372                          mdb_warn("failed to read dispq_t at %p", disp.disp_q);
3373 3373                          return (WALK_ERR);
3374 3374                  }
3375 3375  
3376 3376                  CPUINFO_INDENT;
3377 3377                  mdb_printf("|\n");
3378 3378  
3379 3379                  CPUINFO_INDENT;
3380 3380                  mdb_printf("+-->  %3s %-*s %s\n", "PRI",
3381 3381                      CPUINFO_TWIDTH, "THREAD", "PROC");
3382 3382  
3383 3383                  for (i = npri - 1; i >= 0; i--) {
3384 3384                          uintptr_t taddr = (uintptr_t)dq[i].dq_first;
3385 3385  
3386 3386                          while (taddr != 0) {
3387 3387                                  if (mdb_vread(&t, sizeof (t), taddr) == -1) {
3388 3388                                          mdb_warn("failed to read kthread_t "
3389 3389                                              "at %p", taddr);
3390 3390                                          return (WALK_ERR);
3391 3391                                  }
3392 3392                                  if (mdb_ctf_vread(&p, "proc_t",
3393 3393                                      "mdb_cpuinfo_proc_t",
3394 3394                                      (uintptr_t)t.t_procp, 0) == -1) {
3395 3395                                          mdb_warn("failed to read proc_t at %p",
3396 3396                                              t.t_procp);
3397 3397                                          return (WALK_ERR);
3398 3398                                  }
3399 3399  
3400 3400                                  CPUINFO_INDENT;
3401 3401                                  mdb_printf("      %3d %0*p %s\n", t.t_pri,
3402 3402                                      CPUINFO_TWIDTH, taddr, p.p_user.u_comm);
3403 3403  
3404 3404                                  taddr = (uintptr_t)t.t_link;
3405 3405                          }
3406 3406                  }
3407 3407                  cid->cid_print_head = TRUE;
3408 3408          }
3409 3409  
3410 3410          while (flagline < nflaglines)
3411 3411                  mdb_printf("%s\n", flagbuf[flagline++]);
3412 3412  
3413 3413          if (cid->cid_print_head)
3414 3414                  mdb_printf("\n");
3415 3415  
3416 3416          return (rval);
3417 3417  }
3418 3418  
3419 3419  int
3420 3420  cpuinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3421 3421  {
3422 3422          uint_t verbose = FALSE;
3423 3423          cpuinfo_data_t cid;
3424 3424  
3425 3425          cid.cid_print_ithr = FALSE;
3426 3426          cid.cid_print_thr = FALSE;
3427 3427          cid.cid_print_flags = FALSE;
3428 3428          cid.cid_print_head = DCMD_HDRSPEC(flags) ? TRUE : FALSE;
3429 3429          cid.cid_cpu = -1;
3430 3430  
3431 3431          if (flags & DCMD_ADDRSPEC)
3432 3432                  cid.cid_cpu = addr;
3433 3433  
3434 3434          if (mdb_getopts(argc, argv,
3435 3435              'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
3436 3436                  return (DCMD_USAGE);
3437 3437  
3438 3438          if (verbose) {
3439 3439                  cid.cid_print_ithr = TRUE;
3440 3440                  cid.cid_print_thr = TRUE;
3441 3441                  cid.cid_print_flags = TRUE;
3442 3442                  cid.cid_print_head = TRUE;
3443 3443          }
3444 3444  
3445 3445          if (cid.cid_print_ithr) {
3446 3446                  int i;
3447 3447  
3448 3448                  cid.cid_ithr = mdb_alloc(sizeof (uintptr_t **)
3449 3449                      * NCPU, UM_SLEEP | UM_GC);
3450 3450  
3451 3451                  for (i = 0; i < NCPU; i++)
3452 3452                          cid.cid_ithr[i] = mdb_zalloc(sizeof (uintptr_t *) *
3453 3453                              NINTR, UM_SLEEP | UM_GC);
3454 3454  
3455 3455                  if (mdb_walk("thread", (mdb_walk_cb_t)cpuinfo_walk_ithread,
3456 3456                      &cid) == -1) {
3457 3457                          mdb_warn("couldn't walk thread");
3458 3458                          return (DCMD_ERR);
3459 3459                  }
3460 3460          }
3461 3461  
3462 3462          if (mdb_walk("cpu", (mdb_walk_cb_t)cpuinfo_walk_cpu, &cid) == -1) {
3463 3463                  mdb_warn("can't walk cpus");
3464 3464                  return (DCMD_ERR);
3465 3465          }
3466 3466  
3467 3467          if (cid.cid_cpu != -1) {
3468 3468                  /*
3469 3469                   * We didn't find this CPU when we walked through the CPUs
3470 3470                   * (i.e. the address specified doesn't show up in the "cpu"
3471 3471                   * walk).  However, the specified address may still correspond
3472 3472                   * to a valid cpu_t (for example, if the specified address is
3473 3473                   * the actual panicking cpu_t and not the cached panic_cpu).
3474 3474                   * Point is:  even if we didn't find it, we still want to try
3475 3475                   * to print the specified address as a cpu_t.
3476 3476                   */
3477 3477                  cpu_t cpu;
3478 3478  
3479 3479                  if (mdb_vread(&cpu, sizeof (cpu), cid.cid_cpu) == -1) {
3480 3480                          mdb_warn("%p is neither a valid CPU ID nor a "
3481 3481                              "valid cpu_t address\n", cid.cid_cpu);
3482 3482                          return (DCMD_ERR);
3483 3483                  }
3484 3484  
3485 3485                  (void) cpuinfo_walk_cpu(cid.cid_cpu, &cpu, &cid);
3486 3486          }
3487 3487  
3488 3488          return (DCMD_OK);
3489 3489  }
3490 3490  
3491 3491  /*ARGSUSED*/
3492 3492  int
3493 3493  flipone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3494 3494  {
3495 3495          int i;
3496 3496  
3497 3497          if (!(flags & DCMD_ADDRSPEC))
3498 3498                  return (DCMD_USAGE);
3499 3499  
3500 3500          for (i = 0; i < sizeof (addr) * NBBY; i++)
3501 3501                  mdb_printf("%p\n", addr ^ (1UL << i));
3502 3502  
3503 3503          return (DCMD_OK);
3504 3504  }
3505 3505  
3506 3506  typedef struct mdb_as2proc_proc {
3507 3507          struct as *p_as;
3508 3508  } mdb_as2proc_proc_t;
3509 3509  
3510 3510  /*ARGSUSED*/
3511 3511  int
3512 3512  as2proc_walk(uintptr_t addr, const void *ignored, struct as **asp)
3513 3513  {
3514 3514          mdb_as2proc_proc_t p;
3515 3515  
3516 3516          mdb_ctf_vread(&p, "proc_t", "mdb_as2proc_proc_t", addr, 0);
3517 3517  
3518 3518          if (p.p_as == *asp)
3519 3519                  mdb_printf("%p\n", addr);
3520 3520          return (WALK_NEXT);
3521 3521  }
3522 3522  
3523 3523  /*ARGSUSED*/
3524 3524  int
3525 3525  as2proc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3526 3526  {
3527 3527          if (!(flags & DCMD_ADDRSPEC) || argc != 0)
3528 3528                  return (DCMD_USAGE);
3529 3529  
3530 3530          if (mdb_walk("proc", (mdb_walk_cb_t)as2proc_walk, &addr) == -1) {
3531 3531                  mdb_warn("failed to walk proc");
3532 3532                  return (DCMD_ERR);
3533 3533          }
3534 3534  
3535 3535          return (DCMD_OK);
3536 3536  }
3537 3537  
3538 3538  typedef struct mdb_ptree_proc {
3539 3539          struct proc     *p_parent;
3540 3540          struct {
3541 3541                  char            u_comm[MAXCOMLEN + 1];
3542 3542          } p_user;
3543 3543  } mdb_ptree_proc_t;
3544 3544  
3545 3545  /*ARGSUSED*/
3546 3546  int
3547 3547  ptree_walk(uintptr_t addr, const void *ignored, void *data)
3548 3548  {
3549 3549          mdb_ptree_proc_t proc;
3550 3550          mdb_ptree_proc_t parent;
3551 3551          int ident = 0;
3552 3552          uintptr_t paddr;
3553 3553  
3554 3554          mdb_ctf_vread(&proc, "proc_t", "mdb_ptree_proc_t", addr, 0);
3555 3555  
3556 3556          for (paddr = (uintptr_t)proc.p_parent; paddr != 0; ident += 5) {
3557 3557                  mdb_ctf_vread(&parent, "proc_t", "mdb_ptree_proc_t", paddr, 0);
3558 3558                  paddr = (uintptr_t)parent.p_parent;
3559 3559          }
3560 3560  
3561 3561          mdb_inc_indent(ident);
3562 3562          mdb_printf("%0?p  %s\n", addr, proc.p_user.u_comm);
3563 3563          mdb_dec_indent(ident);
3564 3564  
3565 3565          return (WALK_NEXT);
3566 3566  }
3567 3567  
3568 3568  void
3569 3569  ptree_ancestors(uintptr_t addr, uintptr_t start)
3570 3570  {
3571 3571          mdb_ptree_proc_t p;
3572 3572  
3573 3573          if (mdb_ctf_vread(&p, "proc_t", "mdb_ptree_proc_t", addr, 0) == -1) {
3574 3574                  mdb_warn("couldn't read ancestor at %p", addr);
3575 3575                  return;
3576 3576          }
3577 3577  
3578 3578          if (p.p_parent != NULL)
3579 3579                  ptree_ancestors((uintptr_t)p.p_parent, start);
3580 3580  
3581 3581          if (addr != start)
3582 3582                  (void) ptree_walk(addr, &p, NULL);
3583 3583  }
3584 3584  
3585 3585  /*ARGSUSED*/
3586 3586  int
3587 3587  ptree(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3588 3588  {
3589 3589          if (!(flags & DCMD_ADDRSPEC))
3590 3590                  addr = 0;
3591 3591          else
3592 3592                  ptree_ancestors(addr, addr);
3593 3593  
3594 3594          if (mdb_pwalk("proc", (mdb_walk_cb_t)ptree_walk, NULL, addr) == -1) {
3595 3595                  mdb_warn("couldn't walk 'proc'");
3596 3596                  return (DCMD_ERR);
3597 3597          }
3598 3598  
3599 3599          return (DCMD_OK);
3600 3600  }
3601 3601  
3602 3602  typedef struct mdb_fd_proc {
3603 3603          struct {
3604 3604                  struct {
3605 3605                          int                     fi_nfiles;
3606 3606                          uf_entry_t *volatile    fi_list;
3607 3607                  } u_finfo;
3608 3608          } p_user;
3609 3609  } mdb_fd_proc_t;
3610 3610  
3611 3611  /*ARGSUSED*/
3612 3612  static int
3613 3613  fd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3614 3614  {
3615 3615          int fdnum;
3616 3616          const mdb_arg_t *argp = &argv[0];
3617 3617          mdb_fd_proc_t p;
3618 3618          uf_entry_t uf;
3619 3619  
3620 3620          if ((flags & DCMD_ADDRSPEC) == 0) {
3621 3621                  mdb_warn("fd doesn't give global information\n");
3622 3622                  return (DCMD_ERR);
3623 3623          }
3624 3624          if (argc != 1)
3625 3625                  return (DCMD_USAGE);
3626 3626  
3627 3627          if (argp->a_type == MDB_TYPE_IMMEDIATE)
3628 3628                  fdnum = argp->a_un.a_val;
3629 3629          else
3630 3630                  fdnum = mdb_strtoull(argp->a_un.a_str);
3631 3631  
3632 3632          if (mdb_ctf_vread(&p, "proc_t", "mdb_fd_proc_t", addr, 0) == -1) {
3633 3633                  mdb_warn("couldn't read proc_t at %p", addr);
3634 3634                  return (DCMD_ERR);
3635 3635          }
3636 3636          if (fdnum > p.p_user.u_finfo.fi_nfiles) {
3637 3637                  mdb_warn("process %p only has %d files open.\n",
3638 3638                      addr, p.p_user.u_finfo.fi_nfiles);
3639 3639                  return (DCMD_ERR);
3640 3640          }
3641 3641          if (mdb_vread(&uf, sizeof (uf_entry_t),
3642 3642              (uintptr_t)&p.p_user.u_finfo.fi_list[fdnum]) == -1) {
3643 3643                  mdb_warn("couldn't read uf_entry_t at %p",
3644 3644                      &p.p_user.u_finfo.fi_list[fdnum]);
3645 3645                  return (DCMD_ERR);
3646 3646          }
3647 3647  
3648 3648          mdb_printf("%p\n", uf.uf_file);
3649 3649          return (DCMD_OK);
3650 3650  }
3651 3651  
3652 3652  /*ARGSUSED*/
3653 3653  static int
3654 3654  pid2proc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3655 3655  {
3656 3656          pid_t pid = (pid_t)addr;
3657 3657  
3658 3658          if (argc != 0)
3659 3659                  return (DCMD_USAGE);
3660 3660  
3661 3661          if ((addr = mdb_pid2proc(pid, NULL)) == 0) {
3662 3662                  mdb_warn("PID 0t%d not found\n", pid);
3663 3663                  return (DCMD_ERR);
3664 3664          }
3665 3665  
3666 3666          mdb_printf("%p\n", addr);
3667 3667          return (DCMD_OK);
3668 3668  }
3669 3669  
3670 3670  static char *sysfile_cmd[] = {
3671 3671          "exclude:",
3672 3672          "include:",
3673 3673          "forceload:",
3674 3674          "rootdev:",
3675 3675          "rootfs:",
3676 3676          "swapdev:",
3677 3677          "swapfs:",
3678 3678          "moddir:",
3679 3679          "set",
3680 3680          "unknown",
3681 3681  };
3682 3682  
3683 3683  static char *sysfile_ops[] = { "", "=", "&", "|" };
3684 3684  
3685 3685  /*ARGSUSED*/
3686 3686  static int
3687 3687  sysfile_vmem_seg(uintptr_t addr, const vmem_seg_t *vsp, void **target)
3688 3688  {
3689 3689          if (vsp->vs_type == VMEM_ALLOC && (void *)vsp->vs_start == *target) {
3690 3690                  *target = NULL;
3691 3691                  return (WALK_DONE);
3692 3692          }
3693 3693          return (WALK_NEXT);
3694 3694  }
3695 3695  
3696 3696  /*ARGSUSED*/
3697 3697  static int
3698 3698  sysfile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3699 3699  {
3700 3700          struct sysparam *sysp, sys;
3701 3701          char var[256];
3702 3702          char modname[256];
3703 3703          char val[256];
3704 3704          char strval[256];
3705 3705          vmem_t *mod_sysfile_arena;
3706 3706          void *straddr;
3707 3707  
3708 3708          if (mdb_readvar(&sysp, "sysparam_hd") == -1) {
3709 3709                  mdb_warn("failed to read sysparam_hd");
3710 3710                  return (DCMD_ERR);
3711 3711          }
3712 3712  
3713 3713          if (mdb_readvar(&mod_sysfile_arena, "mod_sysfile_arena") == -1) {
3714 3714                  mdb_warn("failed to read mod_sysfile_arena");
3715 3715                  return (DCMD_ERR);
3716 3716          }
3717 3717  
3718 3718          while (sysp != NULL) {
3719 3719                  var[0] = '\0';
3720 3720                  val[0] = '\0';
3721 3721                  modname[0] = '\0';
3722 3722                  if (mdb_vread(&sys, sizeof (sys), (uintptr_t)sysp) == -1) {
3723 3723                          mdb_warn("couldn't read sysparam %p", sysp);
3724 3724                          return (DCMD_ERR);
3725 3725                  }
3726 3726                  if (sys.sys_modnam != NULL &&
3727 3727                      mdb_readstr(modname, 256,
3728 3728                      (uintptr_t)sys.sys_modnam) == -1) {
3729 3729                          mdb_warn("couldn't read modname in %p", sysp);
3730 3730                          return (DCMD_ERR);
3731 3731                  }
3732 3732                  if (sys.sys_ptr != NULL &&
3733 3733                      mdb_readstr(var, 256, (uintptr_t)sys.sys_ptr) == -1) {
3734 3734                          mdb_warn("couldn't read ptr in %p", sysp);
3735 3735                          return (DCMD_ERR);
3736 3736                  }
3737 3737                  if (sys.sys_op != SETOP_NONE) {
3738 3738                          /*
3739 3739                           * Is this an int or a string?  We determine this
3740 3740                           * by checking whether straddr is contained in
3741 3741                           * mod_sysfile_arena.  If so, the walker will set
3742 3742                           * straddr to NULL.
3743 3743                           */
3744 3744                          straddr = (void *)(uintptr_t)sys.sys_info;
3745 3745                          if (sys.sys_op == SETOP_ASSIGN &&
3746 3746                              sys.sys_info != 0 &&
3747 3747                              mdb_pwalk("vmem_seg",
3748 3748                              (mdb_walk_cb_t)sysfile_vmem_seg, &straddr,
3749 3749                              (uintptr_t)mod_sysfile_arena) == 0 &&
3750 3750                              straddr == NULL &&
3751 3751                              mdb_readstr(strval, 256,
3752 3752                              (uintptr_t)sys.sys_info) != -1) {
3753 3753                                  (void) mdb_snprintf(val, sizeof (val), "\"%s\"",
3754 3754                                      strval);
3755 3755                          } else {
3756 3756                                  (void) mdb_snprintf(val, sizeof (val),
3757 3757                                      "0x%llx [0t%llu]", sys.sys_info,
3758 3758                                      sys.sys_info);
3759 3759                          }
3760 3760                  }
3761 3761                  mdb_printf("%s %s%s%s%s%s\n", sysfile_cmd[sys.sys_type],
3762 3762                      modname, modname[0] == '\0' ? "" : ":",
3763 3763                      var, sysfile_ops[sys.sys_op], val);
3764 3764  
3765 3765                  sysp = sys.sys_next;
3766 3766          }
3767 3767  
3768 3768          return (DCMD_OK);
3769 3769  }
3770 3770  
3771 3771  int
3772 3772  didmatch(uintptr_t addr, const kthread_t *thr, kt_did_t *didp)
3773 3773  {
3774 3774  
3775 3775          if (*didp == thr->t_did) {
3776 3776                  mdb_printf("%p\n", addr);
3777 3777                  return (WALK_DONE);
3778 3778          } else
3779 3779                  return (WALK_NEXT);
3780 3780  }
3781 3781  
3782 3782  /*ARGSUSED*/
3783 3783  int
3784 3784  did2thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3785 3785  {
3786 3786          const mdb_arg_t *argp = &argv[0];
3787 3787          kt_did_t        did;
3788 3788  
3789 3789          if (argc != 1)
3790 3790                  return (DCMD_USAGE);
3791 3791  
3792 3792          did = (kt_did_t)mdb_strtoull(argp->a_un.a_str);
3793 3793  
3794 3794          if (mdb_walk("thread", (mdb_walk_cb_t)didmatch, (void *)&did) == -1) {
3795 3795                  mdb_warn("failed to walk thread");
3796 3796                  return (DCMD_ERR);
3797 3797  
3798 3798          }
3799 3799          return (DCMD_OK);
3800 3800  
3801 3801  }
3802 3802  
3803 3803  static int
3804 3804  errorq_walk_init(mdb_walk_state_t *wsp)
3805 3805  {
3806 3806          if (wsp->walk_addr == 0 &&
3807 3807              mdb_readvar(&wsp->walk_addr, "errorq_list") == -1) {
3808 3808                  mdb_warn("failed to read errorq_list");
3809 3809                  return (WALK_ERR);
3810 3810          }
3811 3811  
3812 3812          return (WALK_NEXT);
3813 3813  }
3814 3814  
3815 3815  static int
3816 3816  errorq_walk_step(mdb_walk_state_t *wsp)
3817 3817  {
3818 3818          uintptr_t addr = wsp->walk_addr;
3819 3819          errorq_t eq;
3820 3820  
3821 3821          if (addr == 0)
3822 3822                  return (WALK_DONE);
3823 3823  
3824 3824          if (mdb_vread(&eq, sizeof (eq), addr) == -1) {
3825 3825                  mdb_warn("failed to read errorq at %p", addr);
3826 3826                  return (WALK_ERR);
3827 3827          }
3828 3828  
3829 3829          wsp->walk_addr = (uintptr_t)eq.eq_next;
3830 3830          return (wsp->walk_callback(addr, &eq, wsp->walk_cbdata));
3831 3831  }
3832 3832  
3833 3833  typedef struct eqd_walk_data {
3834 3834          uintptr_t *eqd_stack;
3835 3835          void *eqd_buf;
3836 3836          ulong_t eqd_qpos;
3837 3837          ulong_t eqd_qlen;
3838 3838          size_t eqd_size;
3839 3839  } eqd_walk_data_t;
3840 3840  
3841 3841  /*
3842 3842   * In order to walk the list of pending error queue elements, we push the
3843 3843   * addresses of the corresponding data buffers in to the eqd_stack array.
3844 3844   * The error lists are in reverse chronological order when iterating using
3845 3845   * eqe_prev, so we then pop things off the top in eqd_walk_step so that the
3846 3846   * walker client gets addresses in order from oldest error to newest error.
3847 3847   */
3848 3848  static void
3849 3849  eqd_push_list(eqd_walk_data_t *eqdp, uintptr_t addr)
3850 3850  {
3851 3851          errorq_elem_t eqe;
3852 3852  
3853 3853          while (addr != 0) {
3854 3854                  if (mdb_vread(&eqe, sizeof (eqe), addr) != sizeof (eqe)) {
3855 3855                          mdb_warn("failed to read errorq element at %p", addr);
3856 3856                          break;
3857 3857                  }
3858 3858  
3859 3859                  if (eqdp->eqd_qpos == eqdp->eqd_qlen) {
3860 3860                          mdb_warn("errorq is overfull -- more than %lu "
3861 3861                              "elems found\n", eqdp->eqd_qlen);
3862 3862                          break;
3863 3863                  }
3864 3864  
3865 3865                  eqdp->eqd_stack[eqdp->eqd_qpos++] = (uintptr_t)eqe.eqe_data;
3866 3866                  addr = (uintptr_t)eqe.eqe_prev;
3867 3867          }
3868 3868  }
3869 3869  
3870 3870  static int
3871 3871  eqd_walk_init(mdb_walk_state_t *wsp)
3872 3872  {
3873 3873          eqd_walk_data_t *eqdp;
3874 3874          errorq_elem_t eqe, *addr;
3875 3875          errorq_t eq;
3876 3876          ulong_t i;
3877 3877  
3878 3878          if (mdb_vread(&eq, sizeof (eq), wsp->walk_addr) == -1) {
3879 3879                  mdb_warn("failed to read errorq at %p", wsp->walk_addr);
3880 3880                  return (WALK_ERR);
3881 3881          }
3882 3882  
3883 3883          if (eq.eq_ptail != NULL &&
3884 3884              mdb_vread(&eqe, sizeof (eqe), (uintptr_t)eq.eq_ptail) == -1) {
3885 3885                  mdb_warn("failed to read errorq element at %p", eq.eq_ptail);
3886 3886                  return (WALK_ERR);
3887 3887          }
3888 3888  
3889 3889          eqdp = mdb_alloc(sizeof (eqd_walk_data_t), UM_SLEEP);
3890 3890          wsp->walk_data = eqdp;
3891 3891  
3892 3892          eqdp->eqd_stack = mdb_zalloc(sizeof (uintptr_t) * eq.eq_qlen, UM_SLEEP);
3893 3893          eqdp->eqd_buf = mdb_alloc(eq.eq_size, UM_SLEEP);
3894 3894          eqdp->eqd_qlen = eq.eq_qlen;
3895 3895          eqdp->eqd_qpos = 0;
3896 3896          eqdp->eqd_size = eq.eq_size;
3897 3897  
3898 3898          /*
3899 3899           * The newest elements in the queue are on the pending list, so we
3900 3900           * push those on to our stack first.
3901 3901           */
3902 3902          eqd_push_list(eqdp, (uintptr_t)eq.eq_pend);
3903 3903  
3904 3904          /*
3905 3905           * If eq_ptail is set, it may point to a subset of the errors on the
3906 3906           * pending list in the event a atomic_cas_ptr() failed; if ptail's
3907 3907           * data is already in our stack, NULL out eq_ptail and ignore it.
3908 3908           */
3909 3909          if (eq.eq_ptail != NULL) {
3910 3910                  for (i = 0; i < eqdp->eqd_qpos; i++) {
3911 3911                          if (eqdp->eqd_stack[i] == (uintptr_t)eqe.eqe_data) {
3912 3912                                  eq.eq_ptail = NULL;
3913 3913                                  break;
3914 3914                          }
3915 3915                  }
3916 3916          }
3917 3917  
3918 3918          /*
3919 3919           * If eq_phead is set, it has the processing list in order from oldest
3920 3920           * to newest.  Use this to recompute eq_ptail as best we can and then
3921 3921           * we nicely fall into eqd_push_list() of eq_ptail below.
3922 3922           */
3923 3923          for (addr = eq.eq_phead; addr != NULL && mdb_vread(&eqe, sizeof (eqe),
3924 3924              (uintptr_t)addr) == sizeof (eqe); addr = eqe.eqe_next)
3925 3925                  eq.eq_ptail = addr;
3926 3926  
3927 3927          /*
3928 3928           * The oldest elements in the queue are on the processing list, subject
3929 3929           * to machinations in the if-clauses above.  Push any such elements.
3930 3930           */
3931 3931          eqd_push_list(eqdp, (uintptr_t)eq.eq_ptail);
3932 3932          return (WALK_NEXT);
3933 3933  }
3934 3934  
3935 3935  static int
3936 3936  eqd_walk_step(mdb_walk_state_t *wsp)
3937 3937  {
3938 3938          eqd_walk_data_t *eqdp = wsp->walk_data;
3939 3939          uintptr_t addr;
3940 3940  
3941 3941          if (eqdp->eqd_qpos == 0)
3942 3942                  return (WALK_DONE);
3943 3943  
3944 3944          addr = eqdp->eqd_stack[--eqdp->eqd_qpos];
3945 3945  
3946 3946          if (mdb_vread(eqdp->eqd_buf, eqdp->eqd_size, addr) != eqdp->eqd_size) {
3947 3947                  mdb_warn("failed to read errorq data at %p", addr);
3948 3948                  return (WALK_ERR);
3949 3949          }
3950 3950  
3951 3951          return (wsp->walk_callback(addr, eqdp->eqd_buf, wsp->walk_cbdata));
3952 3952  }
3953 3953  
3954 3954  static void
3955 3955  eqd_walk_fini(mdb_walk_state_t *wsp)
3956 3956  {
3957 3957          eqd_walk_data_t *eqdp = wsp->walk_data;
3958 3958  
3959 3959          mdb_free(eqdp->eqd_stack, sizeof (uintptr_t) * eqdp->eqd_qlen);
3960 3960          mdb_free(eqdp->eqd_buf, eqdp->eqd_size);
3961 3961          mdb_free(eqdp, sizeof (eqd_walk_data_t));
3962 3962  }
3963 3963  
3964 3964  #define EQKSVAL(eqv, what) (eqv.eq_kstat.what.value.ui64)
3965 3965  
3966 3966  static int
3967 3967  errorq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3968 3968  {
3969 3969          int i;
3970 3970          errorq_t eq;
3971 3971          uint_t opt_v = FALSE;
3972 3972  
3973 3973          if (!(flags & DCMD_ADDRSPEC)) {
3974 3974                  if (mdb_walk_dcmd("errorq", "errorq", argc, argv) == -1) {
3975 3975                          mdb_warn("can't walk 'errorq'");
3976 3976                          return (DCMD_ERR);
3977 3977                  }
3978 3978                  return (DCMD_OK);
3979 3979          }
3980 3980  
3981 3981          i = mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL);
3982 3982          argc -= i;
3983 3983          argv += i;
3984 3984  
3985 3985          if (argc != 0)
3986 3986                  return (DCMD_USAGE);
3987 3987  
3988 3988          if (opt_v || DCMD_HDRSPEC(flags)) {
3989 3989                  mdb_printf("%<u>%-11s %-16s %1s %1s %1s ",
3990 3990                      "ADDR", "NAME", "S", "V", "N");
3991 3991                  if (!opt_v) {
3992 3992                          mdb_printf("%7s %7s %7s%</u>\n",
3993 3993                              "ACCEPT", "DROP", "LOG");
3994 3994                  } else {
3995 3995                          mdb_printf("%5s %6s %6s %3s %16s%</u>\n",
3996 3996                              "KSTAT", "QLEN", "SIZE", "IPL", "FUNC");
3997 3997                  }
3998 3998          }
3999 3999  
4000 4000          if (mdb_vread(&eq, sizeof (eq), addr) != sizeof (eq)) {
4001 4001                  mdb_warn("failed to read errorq at %p", addr);
4002 4002                  return (DCMD_ERR);
4003 4003          }
4004 4004  
4005 4005          mdb_printf("%-11p %-16s %c %c %c ", addr, eq.eq_name,
4006 4006              (eq.eq_flags & ERRORQ_ACTIVE) ? '+' : '-',
4007 4007              (eq.eq_flags & ERRORQ_VITAL) ? '!' : ' ',
4008 4008              (eq.eq_flags & ERRORQ_NVLIST) ? '*' : ' ');
4009 4009  
4010 4010          if (!opt_v) {
4011 4011                  mdb_printf("%7llu %7llu %7llu\n",
4012 4012                      EQKSVAL(eq, eqk_dispatched) + EQKSVAL(eq, eqk_committed),
4013 4013                      EQKSVAL(eq, eqk_dropped) + EQKSVAL(eq, eqk_reserve_fail) +
4014 4014                      EQKSVAL(eq, eqk_commit_fail), EQKSVAL(eq, eqk_logged));
4015 4015          } else {
4016 4016                  mdb_printf("%5s %6lu %6lu %3u %a\n",
4017 4017                      "  |  ", eq.eq_qlen, eq.eq_size, eq.eq_ipl, eq.eq_func);
4018 4018                  mdb_printf("%38s\n%41s"
4019 4019                      "%12s %llu\n"
4020 4020                      "%53s %llu\n"
4021 4021                      "%53s %llu\n"
4022 4022                      "%53s %llu\n"
4023 4023                      "%53s %llu\n"
4024 4024                      "%53s %llu\n"
4025 4025                      "%53s %llu\n"
4026 4026                      "%53s %llu\n\n",
4027 4027                      "|", "+-> ",
4028 4028                      "DISPATCHED",       EQKSVAL(eq, eqk_dispatched),
4029 4029                      "DROPPED",          EQKSVAL(eq, eqk_dropped),
4030 4030                      "LOGGED",           EQKSVAL(eq, eqk_logged),
4031 4031                      "RESERVED",         EQKSVAL(eq, eqk_reserved),
4032 4032                      "RESERVE FAIL",     EQKSVAL(eq, eqk_reserve_fail),
4033 4033                      "COMMITTED",        EQKSVAL(eq, eqk_committed),
4034 4034                      "COMMIT FAIL",      EQKSVAL(eq, eqk_commit_fail),
4035 4035                      "CANCELLED",        EQKSVAL(eq, eqk_cancelled));
4036 4036          }
4037 4037  
4038 4038          return (DCMD_OK);
4039 4039  }
4040 4040  
4041 4041  /*ARGSUSED*/
4042 4042  static int
4043 4043  panicinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4044 4044  {
4045 4045          cpu_t panic_cpu;
4046 4046          kthread_t *panic_thread;
4047 4047          void *buf;
4048 4048          panic_data_t *pd;
4049 4049          int i, n;
4050 4050  
4051 4051          if (!mdb_prop_postmortem) {
4052 4052                  mdb_warn("panicinfo can only be run on a system "
4053 4053                      "dump; see dumpadm(1M)\n");
4054 4054                  return (DCMD_ERR);
4055 4055          }
4056 4056  
4057 4057          if (flags & DCMD_ADDRSPEC || argc != 0)
4058 4058                  return (DCMD_USAGE);
4059 4059  
4060 4060          if (mdb_readsym(&panic_cpu, sizeof (cpu_t), "panic_cpu") == -1)
4061 4061                  mdb_warn("failed to read 'panic_cpu'");
4062 4062          else
4063 4063                  mdb_printf("%16s %?d\n", "cpu", panic_cpu.cpu_id);
4064 4064  
4065 4065          if (mdb_readvar(&panic_thread, "panic_thread") == -1)
4066 4066                  mdb_warn("failed to read 'panic_thread'");
4067 4067          else
4068 4068                  mdb_printf("%16s %?p\n", "thread", panic_thread);
4069 4069  
4070 4070          buf = mdb_alloc(PANICBUFSIZE, UM_SLEEP);
4071 4071          pd = (panic_data_t *)buf;
4072 4072  
4073 4073          if (mdb_readsym(buf, PANICBUFSIZE, "panicbuf") == -1 ||
4074 4074              pd->pd_version != PANICBUFVERS) {
4075 4075                  mdb_warn("failed to read 'panicbuf'");
4076 4076                  mdb_free(buf, PANICBUFSIZE);
4077 4077                  return (DCMD_ERR);
4078 4078          }
4079 4079  
4080 4080          mdb_printf("%16s %s\n", "message",  (char *)buf + pd->pd_msgoff);
4081 4081  
4082 4082          n = (pd->pd_msgoff - (sizeof (panic_data_t) -
4083 4083              sizeof (panic_nv_t))) / sizeof (panic_nv_t);
4084 4084  
4085 4085          for (i = 0; i < n; i++)
4086 4086                  mdb_printf("%16s %?llx\n",
4087 4087                      pd->pd_nvdata[i].pnv_name, pd->pd_nvdata[i].pnv_value);
4088 4088  
4089 4089          mdb_free(buf, PANICBUFSIZE);
4090 4090          return (DCMD_OK);
4091 4091  }
4092 4092  
4093 4093  /*
4094 4094   * ::time dcmd, which will print a hires timestamp of when we entered the
4095 4095   * debugger, or the lbolt value if used with the -l option.
4096 4096   *
4097 4097   */
4098 4098  /*ARGSUSED*/
4099 4099  static int
4100 4100  time(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4101 4101  {
4102 4102          uint_t opt_dec = FALSE;
4103 4103          uint_t opt_lbolt = FALSE;
4104 4104          uint_t opt_hex = FALSE;
4105 4105          const char *fmt;
4106 4106          hrtime_t result;
4107 4107  
4108 4108          if (mdb_getopts(argc, argv,
4109 4109              'd', MDB_OPT_SETBITS, TRUE, &opt_dec,
4110 4110              'l', MDB_OPT_SETBITS, TRUE, &opt_lbolt,
4111 4111              'x', MDB_OPT_SETBITS, TRUE, &opt_hex,
4112 4112              NULL) != argc)
4113 4113                  return (DCMD_USAGE);
4114 4114  
4115 4115          if (opt_dec && opt_hex)
4116 4116                  return (DCMD_USAGE);
4117 4117  
4118 4118          result = opt_lbolt ? mdb_get_lbolt() : mdb_gethrtime();
4119 4119          fmt =
4120 4120              opt_hex ? "0x%llx\n" :
4121 4121              opt_dec ? "0t%lld\n" : "%#llr\n";
4122 4122  
4123 4123          mdb_printf(fmt, result);
4124 4124          return (DCMD_OK);
4125 4125  }
4126 4126  
4127 4127  void
4128 4128  time_help(void)
4129 4129  {
4130 4130          mdb_printf("Prints the system time in nanoseconds.\n\n"
4131 4131              "::time will return the timestamp at which we dropped into, \n"
4132 4132              "if called from, kmdb(1); the core dump's high resolution \n"
4133 4133              "time if inspecting one; or the running hires time if we're \n"
4134 4134              "looking at a live system.\n\n"
4135 4135              "Switches:\n"
4136 4136              "  -d   report times in decimal\n"
4137 4137              "  -l   prints the number of clock ticks since system boot\n"
4138 4138              "  -x   report times in hexadecimal\n");
4139 4139  }
4140 4140  
4141 4141  extern int cmd_refstr(uintptr_t, uint_t, int, const mdb_arg_t *);
4142 4142  
4143 4143  static const mdb_dcmd_t dcmds[] = {
4144 4144  
4145 4145          /* from genunix.c */
4146 4146          { "as2proc", ":", "convert as to proc_t address", as2proc },
4147 4147          { "binding_hash_entry", ":", "print driver names hash table entry",
4148 4148                  binding_hash_entry },
4149 4149          { "callout", "?[-r|n] [-s|l] [-xhB] [-t | -ab nsec [-dkD]]"
4150 4150              " [-C addr | -S seqid] [-f name|addr] [-p name| addr] [-T|L [-E]]"
4151 4151              " [-FivVA]",
4152 4152              "display callouts", callout, callout_help },
4153 4153          { "calloutid", "[-d|v] xid", "print callout by extended id",
4154 4154              calloutid, calloutid_help },
4155 4155          { "class", NULL, "print process scheduler classes", class },
4156 4156          { "cpuinfo", "?[-v]", "print CPUs and runnable threads", cpuinfo },
4157 4157          { "did2thread", "? kt_did", "find kernel thread for this id",
4158 4158                  did2thread },
4159 4159          { "errorq", "?[-v]", "display kernel error queues", errorq },
4160 4160          { "fd", ":[fd num]", "get a file pointer from an fd", fd },
4161 4161          { "flipone", ":", "the vik_rev_level 2 special", flipone },
4162 4162          { "lminfo", NULL, "print lock manager information", lminfo },
4163 4163          { "ndi_event_hdl", "?", "print ndi_event_hdl", ndi_event_hdl },
4164 4164          { "panicinfo", NULL, "print panic information", panicinfo },
4165 4165          { "pid2proc", "?", "convert PID to proc_t address", pid2proc },
4166 4166          { "project", NULL, "display kernel project(s)", project },
4167 4167          { "ps", "[-fltzTP]", "list processes (and associated thr,lwp)", ps,
4168 4168              ps_help },
4169 4169          { "pflags", NULL, "display various proc_t flags", pflags },
4170 4170          { "pgrep", "[-x] [-n | -o] pattern",
4171 4171                  "pattern match against all processes", pgrep },
4172 4172          { "ptree", NULL, "print process tree", ptree },
4173 4173          { "refstr", NULL, "print string from a refstr_t", cmd_refstr, NULL },
4174 4174          { "sysevent", "?[-sv]", "print sysevent pending or sent queue",
4175 4175                  sysevent},
4176 4176          { "sysevent_channel", "?", "print sysevent channel database",
4177 4177                  sysevent_channel},
4178 4178          { "sysevent_class_list", ":", "print sysevent class list",
4179 4179                  sysevent_class_list},
4180 4180          { "sysevent_subclass_list", ":",
4181 4181                  "print sysevent subclass list", sysevent_subclass_list},
4182 4182          { "system", NULL, "print contents of /etc/system file", sysfile },
4183 4183          { "task", NULL, "display kernel task(s)", task },
4184 4184          { "time", "[-dlx]", "display system time", time, time_help },
4185 4185          { "vnode2path", ":[-F]", "vnode address to pathname", vnode2path },
4186 4186          { "whereopen", ":", "given a vnode, dumps procs which have it open",
4187 4187              whereopen },
4188 4188  
4189 4189          /* from bio.c */
4190 4190          { "bufpagefind", ":addr", "find page_t on buf_t list", bufpagefind },
4191 4191  
4192 4192          /* from bitset.c */
4193 4193          { "bitset", ":", "display a bitset", bitset, bitset_help },
4194 4194  
4195 4195          /* from contract.c */
4196 4196          { "contract", "?", "display a contract", cmd_contract },
4197 4197          { "ctevent", ":", "display a contract event", cmd_ctevent },
4198 4198          { "ctid", ":", "convert id to a contract pointer", cmd_ctid },
4199 4199  
4200 4200          /* from cpupart.c */
4201 4201          { "cpupart", "?[-v]", "print cpu partition info", cpupart },
4202 4202  
4203 4203          /* from cred.c */
4204 4204          { "cred", ":[-v]", "display a credential", cmd_cred },
4205 4205          { "credgrp", ":[-v]", "display cred_t groups", cmd_credgrp },
4206 4206          { "credsid", ":[-v]", "display a credsid_t", cmd_credsid },
4207 4207          { "ksidlist", ":[-v]", "display a ksidlist_t", cmd_ksidlist },
4208 4208  
4209 4209          /* from cyclic.c */
4210 4210          { "cyccover", NULL, "dump cyclic coverage information", cyccover },
4211 4211          { "cycid", "?", "dump a cyclic id", cycid },
4212 4212          { "cycinfo", "?", "dump cyc_cpu info", cycinfo },
4213 4213          { "cyclic", ":", "developer information", cyclic },
4214 4214          { "cyctrace", "?", "dump cyclic trace buffer", cyctrace },
4215 4215  
4216 4216          /* from damap.c */
4217 4217          { "damap", ":", "display a damap_t", damap, damap_help },
4218 4218  
4219 4219          /* from ddi_periodic.c */
4220 4220          { "ddi_periodic", "?[-v]", "dump ddi_periodic_impl_t info", dprinfo },
4221 4221  
4222 4222          /* from devinfo.c */
4223 4223          { "devbindings", "?[-qs] [device-name | major-num]",
4224 4224              "print devinfo nodes bound to device-name or major-num",
4225 4225              devbindings, devinfo_help },
4226 4226          { "devinfo", ":[-qsd] [-b bus]", "detailed devinfo of one node",
4227 4227              devinfo, devinfo_help },
4228 4228          { "devinfo_audit", ":[-v]", "devinfo configuration audit record",
4229 4229              devinfo_audit },
4230 4230          { "devinfo_audit_log", "?[-v]", "system wide devinfo configuration log",
4231 4231              devinfo_audit_log },
4232 4232          { "devinfo_audit_node", ":[-v]", "devinfo node configuration history",
4233 4233              devinfo_audit_node },
4234 4234          { "devinfo2driver", ":", "find driver name for this devinfo node",
4235 4235              devinfo2driver },
4236 4236          { "devnames", "?[-vm] [num]", "print devnames array", devnames },
4237 4237          { "dev2major", "?<dev_t>", "convert dev_t to a major number",
4238 4238              dev2major },
4239 4239          { "dev2minor", "?<dev_t>", "convert dev_t to a minor number",
4240 4240              dev2minor },
4241 4241          { "devt", "?<dev_t>", "display a dev_t's major and minor numbers",
4242 4242              devt },
4243 4243          { "major2name", "?<major-num>", "convert major number to dev name",
4244 4244              major2name },
4245 4245          { "minornodes", ":", "given a devinfo node, print its minor nodes",
4246 4246              minornodes },
4247 4247          { "modctl2devinfo", ":", "given a modctl, list its devinfos",
4248 4248              modctl2devinfo },
4249 4249          { "name2major", "<dev-name>", "convert dev name to major number",
4250 4250              name2major },
4251 4251          { "prtconf", "?[-vpc] [-d driver] [-i inst]", "print devinfo tree",
4252 4252              prtconf, prtconf_help },
4253 4253          { "softstate", ":<instance>", "retrieve soft-state pointer",
4254 4254              softstate },
4255 4255          { "devinfo_fm", ":", "devinfo fault managment configuration",
4256 4256              devinfo_fm },
4257 4257          { "devinfo_fmce", ":", "devinfo fault managment cache entry",
4258 4258              devinfo_fmce},
4259 4259  
4260 4260          /* from findstack.c */
4261 4261          { "findstack", ":[-v]", "find kernel thread stack", findstack },
4262 4262          { "findstack_debug", NULL, "toggle findstack debugging",
4263 4263                  findstack_debug },
4264 4264          { "stacks", "?[-afiv] [-c func] [-C func] [-m module] [-M module] "
4265 4265                  "[-s sobj | -S sobj] [-t tstate | -T tstate]",
4266 4266                  "print unique kernel thread stacks",
4267 4267                  stacks, stacks_help },
4268 4268  
4269 4269          /* from fm.c */
4270 4270          { "ereport", "[-v]", "print ereports logged in dump",
4271 4271              ereport },
4272 4272  
4273 4273          /* from group.c */
4274 4274          { "group", "?[-q]", "display a group", group},
4275 4275  
4276 4276          /* from hotplug.c */
4277 4277          { "hotplug", "?[-p]", "display a registered hotplug attachment",
4278 4278              hotplug, hotplug_help },
4279 4279  
4280 4280          /* from irm.c */
4281 4281          { "irmpools", NULL, "display interrupt pools", irmpools_dcmd },
4282 4282          { "irmreqs", NULL, "display interrupt requests in an interrupt pool",
4283 4283              irmreqs_dcmd },
4284 4284          { "irmreq", NULL, "display an interrupt request", irmreq_dcmd },
4285 4285  
  
    | 
      ↓ open down ↓ | 
    4285 lines elided | 
    
      ↑ open up ↑ | 
  
4286 4286          /* from kgrep.c + genunix.c */
4287 4287          { "kgrep", KGREP_USAGE, "search kernel as for a pointer", kgrep,
4288 4288                  kgrep_help },
4289 4289  
4290 4290          /* from kmem.c */
4291 4291          { "allocdby", ":", "given a thread, print its allocated buffers",
4292 4292                  allocdby },
4293 4293          { "bufctl", ":[-vh] [-a addr] [-c caller] [-e earliest] [-l latest] "
4294 4294                  "[-t thd]", "print or filter a bufctl", bufctl, bufctl_help },
4295 4295          { "freedby", ":", "given a thread, print its freed buffers", freedby },
4296      -        { "kmalog", "?[ fail | slab ]",
4297      -            "display kmem transaction log and stack traces", kmalog },
     4296 +        { "kmalog", "?[ fail | slab | zerosized ]",
     4297 +            "display kmem transaction log and stack traces for specified type",
     4298 +            kmalog },
4298 4299          { "kmastat", "[-kmg]", "kernel memory allocator stats",
4299 4300              kmastat },
4300 4301          { "kmausers", "?[-ef] [cache ...]", "current medium and large users "
4301 4302                  "of the kmem allocator", kmausers, kmausers_help },
4302 4303          { "kmem_cache", "?[-n name]",
4303 4304                  "print kernel memory caches", kmem_cache, kmem_cache_help},
4304 4305          { "kmem_slabs", "?[-v] [-n cache] [-N cache] [-b maxbins] "
4305 4306                  "[-B minbinsize]", "display slab usage per kmem cache",
4306 4307                  kmem_slabs, kmem_slabs_help },
4307 4308          { "kmem_debug", NULL, "toggle kmem dcmd/walk debugging", kmem_debug },
4308 4309          { "kmem_log", "?[-b]", "dump kmem transaction log", kmem_log },
4309 4310          { "kmem_verify", "?", "check integrity of kmem-managed memory",
4310 4311                  kmem_verify },
4311 4312          { "vmem", "?", "print a vmem_t", vmem },
4312 4313          { "vmem_seg", ":[-sv] [-c caller] [-e earliest] [-l latest] "
4313 4314                  "[-m minsize] [-M maxsize] [-t thread] [-T type]",
4314 4315                  "print or filter a vmem_seg", vmem_seg, vmem_seg_help },
4315 4316          { "whatthread", ":[-v]", "print threads whose stack contains the "
4316 4317                  "given address", whatthread },
4317 4318  
4318 4319          /* from ldi.c */
4319 4320          { "ldi_handle", "?[-i]", "display a layered driver handle",
4320 4321              ldi_handle, ldi_handle_help },
4321 4322          { "ldi_ident", NULL, "display a layered driver identifier",
4322 4323              ldi_ident, ldi_ident_help },
4323 4324  
4324 4325          /* from leaky.c + leaky_subr.c */
4325 4326          { "findleaks", FINDLEAKS_USAGE,
4326 4327              "search for potential kernel memory leaks", findleaks,
4327 4328              findleaks_help },
4328 4329  
4329 4330          /* from lgrp.c */
4330 4331          { "lgrp", "?[-q] [-p | -Pih]", "display an lgrp", lgrp},
4331 4332          { "lgrp_set", "", "display bitmask of lgroups as a list", lgrp_set},
4332 4333  
4333 4334          /* from log.c */
4334 4335          { "msgbuf", "?[-v]", "print most recent console messages", msgbuf },
4335 4336  
4336 4337          /* from mdi.c */
4337 4338          { "mdipi", NULL, "given a path, dump mdi_pathinfo "
4338 4339                  "and detailed pi_prop list", mdipi },
4339 4340          { "mdiprops", NULL, "given a pi_prop, dump the pi_prop list",
4340 4341                  mdiprops },
4341 4342          { "mdiphci", NULL, "given a phci, dump mdi_phci and "
4342 4343                  "list all paths", mdiphci },
4343 4344          { "mdivhci", NULL, "given a vhci, dump mdi_vhci and list "
4344 4345                  "all phcis", mdivhci },
4345 4346          { "mdiclient_paths", NULL, "given a path, walk mdi_pathinfo "
4346 4347                  "client links", mdiclient_paths },
4347 4348          { "mdiphci_paths", NULL, "given a path, walk through mdi_pathinfo "
4348 4349                  "phci links", mdiphci_paths },
4349 4350          { "mdiphcis", NULL, "given a phci, walk through mdi_phci ph_next links",
4350 4351                  mdiphcis },
4351 4352  
4352 4353          /* from memory.c */
4353 4354          { "addr2smap", ":[offset]", "translate address to smap", addr2smap },
4354 4355          { "memlist", "?[-iav]", "display a struct memlist", memlist },
4355 4356          { "memstat", NULL, "display memory usage summary", memstat },
4356 4357          { "page", "?", "display a summarized page_t", page },
4357 4358          { "pagelookup", "?[-v vp] [-o offset]",
4358 4359                  "find the page_t with the name {vp, offset}",
4359 4360                  pagelookup, pagelookup_help },
4360 4361          { "page_num2pp", ":", "find the page_t for a given page frame number",
4361 4362                  page_num2pp },
4362 4363          { "pmap", ":[-q]", "print process memory map", pmap },
4363 4364          { "seg", ":", "print address space segment", seg },
4364 4365          { "swapinfo", "?", "display a struct swapinfo", swapinfof },
4365 4366          { "vnode2smap", ":[offset]", "translate vnode to smap", vnode2smap },
4366 4367  
4367 4368          /* from mmd.c */
4368 4369          { "multidata", ":[-sv]", "display a summarized multidata_t",
4369 4370                  multidata },
4370 4371          { "pattbl", ":", "display a summarized multidata attribute table",
4371 4372                  pattbl },
4372 4373          { "pattr2multidata", ":", "print multidata pointer from pattr_t",
4373 4374                  pattr2multidata },
4374 4375          { "pdesc2slab", ":", "print pdesc slab pointer from pdesc_t",
4375 4376                  pdesc2slab },
4376 4377          { "pdesc_verify", ":", "verify integrity of a pdesc_t", pdesc_verify },
4377 4378          { "slab2multidata", ":", "print multidata pointer from pdesc_slab_t",
4378 4379                  slab2multidata },
4379 4380  
4380 4381          /* from modhash.c */
4381 4382          { "modhash", "?[-ceht] [-k key] [-v val] [-i index]",
4382 4383                  "display information about one or all mod_hash structures",
4383 4384                  modhash, modhash_help },
4384 4385          { "modent", ":[-k | -v | -t type]",
4385 4386                  "display information about a mod_hash_entry", modent,
4386 4387                  modent_help },
4387 4388  
4388 4389          /* from net.c */
4389 4390          { "dladm", "?<sub-command> [flags]", "show data link information",
4390 4391                  dladm, dladm_help },
4391 4392          { "mi", ":[-p] [-d | -m]", "filter and display MI object or payload",
4392 4393                  mi },
4393 4394          { "netstat", "[-arv] [-f inet | inet6 | unix] [-P tcp | udp | icmp]",
4394 4395                  "show network statistics", netstat },
4395 4396          { "sonode", "?[-f inet | inet6 | unix | #] "
4396 4397                  "[-t stream | dgram | raw | #] [-p #]",
4397 4398                  "filter and display sonode", sonode },
4398 4399  
4399 4400          /* from netstack.c */
4400 4401          { "netstack", "", "show stack instances", netstack },
4401 4402          { "netstackid2netstack", ":",
4402 4403                  "translate a netstack id to its netstack_t",
4403 4404                  netstackid2netstack },
4404 4405  
4405 4406          /* from nvpair.c */
4406 4407          { NVPAIR_DCMD_NAME, NVPAIR_DCMD_USAGE, NVPAIR_DCMD_DESCR,
4407 4408                  nvpair_print },
4408 4409          { NVLIST_DCMD_NAME, NVLIST_DCMD_USAGE, NVLIST_DCMD_DESCR,
4409 4410                  print_nvlist },
4410 4411  
4411 4412          /* from pg.c */
4412 4413          { "pg", "?[-q]", "display a pg", pg},
4413 4414  
4414 4415          /* from rctl.c */
4415 4416          { "rctl_dict", "?", "print systemwide default rctl definitions",
4416 4417                  rctl_dict },
4417 4418          { "rctl_list", ":[handle]", "print rctls for the given proc",
4418 4419                  rctl_list },
4419 4420          { "rctl", ":[handle]", "print a rctl_t, only if it matches the handle",
4420 4421                  rctl },
4421 4422          { "rctl_validate", ":[-v] [-n #]", "test resource control value "
4422 4423                  "sequence", rctl_validate },
4423 4424  
4424 4425          /* from sobj.c */
4425 4426          { "rwlock", ":", "dump out a readers/writer lock", rwlock },
4426 4427          { "mutex", ":[-f]", "dump out an adaptive or spin mutex", mutex,
4427 4428                  mutex_help },
4428 4429          { "sobj2ts", ":", "perform turnstile lookup on synch object", sobj2ts },
4429 4430          { "wchaninfo", "?[-v]", "dump condition variable", wchaninfo },
4430 4431          { "turnstile", "?", "display a turnstile", turnstile },
4431 4432  
4432 4433          /* from stream.c */
4433 4434          { "mblk", ":[-q|v] [-f|F flag] [-t|T type] [-l|L|B len] [-d dbaddr]",
4434 4435                  "print an mblk", mblk_prt, mblk_help },
4435 4436          { "mblk_verify", "?", "verify integrity of an mblk", mblk_verify },
4436 4437          { "mblk2dblk", ":", "convert mblk_t address to dblk_t address",
4437 4438                  mblk2dblk },
4438 4439          { "q2otherq", ":", "print peer queue for a given queue", q2otherq },
4439 4440          { "q2rdq", ":", "print read queue for a given queue", q2rdq },
4440 4441          { "q2syncq", ":", "print syncq for a given queue", q2syncq },
4441 4442          { "q2stream", ":", "print stream pointer for a given queue", q2stream },
4442 4443          { "q2wrq", ":", "print write queue for a given queue", q2wrq },
4443 4444          { "queue", ":[-q|v] [-m mod] [-f flag] [-F flag] [-s syncq_addr]",
4444 4445                  "filter and display STREAM queue", queue, queue_help },
4445 4446          { "stdata", ":[-q|v] [-f flag] [-F flag]",
4446 4447                  "filter and display STREAM head", stdata, stdata_help },
4447 4448          { "str2mate", ":", "print mate of this stream", str2mate },
4448 4449          { "str2wrq", ":", "print write queue of this stream", str2wrq },
4449 4450          { "stream", ":", "display STREAM", stream },
4450 4451          { "strftevent", ":", "print STREAMS flow trace event", strftevent },
4451 4452          { "syncq", ":[-q|v] [-f flag] [-F flag] [-t type] [-T type]",
4452 4453                  "filter and display STREAM sync queue", syncq, syncq_help },
4453 4454          { "syncq2q", ":", "print queue for a given syncq", syncq2q },
4454 4455  
4455 4456          /* from taskq.c */
4456 4457          { "taskq", ":[-atT] [-m min_maxq] [-n name]",
4457 4458              "display a taskq", taskq, taskq_help },
4458 4459          { "taskq_entry", ":", "display a taskq_ent_t", taskq_ent },
4459 4460  
4460 4461          /* from thread.c */
4461 4462          { "thread", "?[-bdfimps]", "display a summarized kthread_t", thread,
4462 4463                  thread_help },
4463 4464          { "threadlist", "?[-t] [-v [count]]",
4464 4465                  "display threads and associated C stack traces", threadlist,
4465 4466                  threadlist_help },
4466 4467          { "stackinfo", "?[-h|-a]", "display kthread_t stack usage", stackinfo,
4467 4468                  stackinfo_help },
4468 4469  
4469 4470          /* from tsd.c */
4470 4471          { "tsd", ":-k key", "print tsd[key-1] for this thread", ttotsd },
4471 4472          { "tsdtot", ":", "find thread with this tsd", tsdtot },
4472 4473  
4473 4474          /*
4474 4475           * typegraph does not work under kmdb, as it requires too much memory
4475 4476           * for its internal data structures.
4476 4477           */
4477 4478  #ifndef _KMDB
4478 4479          /* from typegraph.c */
4479 4480          { "findlocks", ":", "find locks held by specified thread", findlocks },
4480 4481          { "findfalse", "?[-v]", "find potentially falsely shared structures",
4481 4482                  findfalse },
4482 4483          { "typegraph", NULL, "build type graph", typegraph },
4483 4484          { "istype", ":type", "manually set object type", istype },
4484 4485          { "notype", ":", "manually clear object type", notype },
4485 4486          { "whattype", ":", "determine object type", whattype },
4486 4487  #endif
4487 4488  
4488 4489          /* from vfs.c */
4489 4490          { "fsinfo", "?[-v]", "print mounted filesystems", fsinfo },
4490 4491          { "pfiles", ":[-fp]", "print process file information", pfiles,
4491 4492                  pfiles_help },
4492 4493  
4493 4494          /* from zone.c */
4494 4495          { "zid2zone", ":", "find the zone_t with the given zone id",
4495 4496                  zid2zone },
4496 4497          { "zone", "?[-r [-v]]", "display kernel zone(s)", zoneprt },
4497 4498          { "zsd", ":[-v] [zsd_key]", "display zone-specific-data entries for "
4498 4499              "selected zones", zsd },
4499 4500  
4500 4501  #ifndef _KMDB
4501 4502          { "gcore", NULL, "generate a user core for the given process",
4502 4503              gcore_dcmd },
4503 4504  #endif
4504 4505  
4505 4506          { NULL }
4506 4507  };
4507 4508  
4508 4509  static const mdb_walker_t walkers[] = {
4509 4510  
4510 4511          /* from genunix.c */
4511 4512          { "callouts_bytime", "walk callouts by list chain (expiration time)",
4512 4513                  callout_walk_init, callout_walk_step, callout_walk_fini,
4513 4514                  (void *)CALLOUT_WALK_BYLIST },
4514 4515          { "callouts_byid", "walk callouts by id hash chain",
4515 4516                  callout_walk_init, callout_walk_step, callout_walk_fini,
4516 4517                  (void *)CALLOUT_WALK_BYID },
4517 4518          { "callout_list", "walk a callout list", callout_list_walk_init,
4518 4519                  callout_list_walk_step, callout_list_walk_fini },
4519 4520          { "callout_table", "walk callout table array", callout_table_walk_init,
4520 4521                  callout_table_walk_step, callout_table_walk_fini },
4521 4522          { "cpu", "walk cpu structures", cpu_walk_init, cpu_walk_step },
4522 4523          { "dnlc", "walk dnlc entries",
4523 4524                  dnlc_walk_init, dnlc_walk_step, dnlc_walk_fini },
4524 4525          { "ereportq_dump", "walk list of ereports in dump error queue",
4525 4526                  ereportq_dump_walk_init, ereportq_dump_walk_step, NULL },
4526 4527          { "ereportq_pend", "walk list of ereports in pending error queue",
4527 4528                  ereportq_pend_walk_init, ereportq_pend_walk_step, NULL },
4528 4529          { "errorq", "walk list of system error queues",
4529 4530                  errorq_walk_init, errorq_walk_step, NULL },
4530 4531          { "errorq_data", "walk pending error queue data buffers",
4531 4532                  eqd_walk_init, eqd_walk_step, eqd_walk_fini },
4532 4533          { "allfile", "given a proc pointer, list all file pointers",
4533 4534                  file_walk_init, allfile_walk_step, file_walk_fini },
4534 4535          { "file", "given a proc pointer, list of open file pointers",
4535 4536                  file_walk_init, file_walk_step, file_walk_fini },
4536 4537          { "lock_descriptor", "walk lock_descriptor_t structures",
4537 4538                  ld_walk_init, ld_walk_step, NULL },
4538 4539          { "lock_graph", "walk lock graph",
4539 4540                  lg_walk_init, lg_walk_step, NULL },
4540 4541          { "port", "given a proc pointer, list of created event ports",
4541 4542                  port_walk_init, port_walk_step, NULL },
4542 4543          { "portev", "given a port pointer, list of events in the queue",
4543 4544                  portev_walk_init, portev_walk_step, portev_walk_fini },
4544 4545          { "proc", "list of active proc_t structures",
4545 4546                  proc_walk_init, proc_walk_step, proc_walk_fini },
4546 4547          { "projects", "walk a list of kernel projects",
4547 4548                  project_walk_init, project_walk_step, NULL },
4548 4549          { "sysevent_pend", "walk sysevent pending queue",
4549 4550                  sysevent_pend_walk_init, sysevent_walk_step,
4550 4551                  sysevent_walk_fini},
4551 4552          { "sysevent_sent", "walk sysevent sent queue", sysevent_sent_walk_init,
4552 4553                  sysevent_walk_step, sysevent_walk_fini},
4553 4554          { "sysevent_channel", "walk sysevent channel subscriptions",
4554 4555                  sysevent_channel_walk_init, sysevent_channel_walk_step,
4555 4556                  sysevent_channel_walk_fini},
4556 4557          { "sysevent_class_list", "walk sysevent subscription's class list",
4557 4558                  sysevent_class_list_walk_init, sysevent_class_list_walk_step,
4558 4559                  sysevent_class_list_walk_fini},
4559 4560          { "sysevent_subclass_list",
4560 4561                  "walk sysevent subscription's subclass list",
4561 4562                  sysevent_subclass_list_walk_init,
4562 4563                  sysevent_subclass_list_walk_step,
4563 4564                  sysevent_subclass_list_walk_fini},
4564 4565          { "task", "given a task pointer, walk its processes",
4565 4566                  task_walk_init, task_walk_step, NULL },
4566 4567  
4567 4568          /* from avl.c */
4568 4569          { AVL_WALK_NAME, AVL_WALK_DESC,
4569 4570                  avl_walk_init, avl_walk_step, avl_walk_fini },
4570 4571  
4571 4572          /* from bio.c */
4572 4573          { "buf", "walk the bio buf hash",
4573 4574                  buf_walk_init, buf_walk_step, buf_walk_fini },
4574 4575  
4575 4576          /* from contract.c */
4576 4577          { "contract", "walk all contracts, or those of the specified type",
4577 4578                  ct_walk_init, generic_walk_step, NULL },
4578 4579          { "ct_event", "walk events on a contract event queue",
4579 4580                  ct_event_walk_init, generic_walk_step, NULL },
4580 4581          { "ct_listener", "walk contract event queue listeners",
4581 4582                  ct_listener_walk_init, generic_walk_step, NULL },
4582 4583  
4583 4584          /* from cpupart.c */
4584 4585          { "cpupart_cpulist", "given an cpupart_t, walk cpus in partition",
4585 4586                  cpupart_cpulist_walk_init, cpupart_cpulist_walk_step,
4586 4587                  NULL },
4587 4588          { "cpupart_walk", "walk the set of cpu partitions",
4588 4589                  cpupart_walk_init, cpupart_walk_step, NULL },
4589 4590  
4590 4591          /* from ctxop.c */
4591 4592          { "ctxop", "walk list of context ops on a thread",
4592 4593                  ctxop_walk_init, ctxop_walk_step, ctxop_walk_fini },
4593 4594  
4594 4595          /* from cyclic.c */
4595 4596          { "cyccpu", "walk per-CPU cyc_cpu structures",
4596 4597                  cyccpu_walk_init, cyccpu_walk_step, NULL },
4597 4598          { "cycomni", "for an omnipresent cyclic, walk cyc_omni_cpu list",
4598 4599                  cycomni_walk_init, cycomni_walk_step, NULL },
4599 4600          { "cyctrace", "walk cyclic trace buffer",
4600 4601                  cyctrace_walk_init, cyctrace_walk_step, cyctrace_walk_fini },
4601 4602  
4602 4603          /* from devinfo.c */
4603 4604          { "binding_hash", "walk all entries in binding hash table",
4604 4605                  binding_hash_walk_init, binding_hash_walk_step, NULL },
4605 4606          { "devinfo", "walk devinfo tree or subtree",
4606 4607                  devinfo_walk_init, devinfo_walk_step, devinfo_walk_fini },
4607 4608          { "devinfo_audit_log", "walk devinfo audit system-wide log",
4608 4609                  devinfo_audit_log_walk_init, devinfo_audit_log_walk_step,
4609 4610                  devinfo_audit_log_walk_fini},
4610 4611          { "devinfo_audit_node", "walk per-devinfo audit history",
4611 4612                  devinfo_audit_node_walk_init, devinfo_audit_node_walk_step,
4612 4613                  devinfo_audit_node_walk_fini},
4613 4614          { "devinfo_children", "walk children of devinfo node",
4614 4615                  devinfo_children_walk_init, devinfo_children_walk_step,
4615 4616                  devinfo_children_walk_fini },
4616 4617          { "devinfo_parents", "walk ancestors of devinfo node",
4617 4618                  devinfo_parents_walk_init, devinfo_parents_walk_step,
4618 4619                  devinfo_parents_walk_fini },
4619 4620          { "devinfo_siblings", "walk siblings of devinfo node",
4620 4621                  devinfo_siblings_walk_init, devinfo_siblings_walk_step, NULL },
4621 4622          { "devi_next", "walk devinfo list",
4622 4623                  NULL, devi_next_walk_step, NULL },
4623 4624          { "devnames", "walk devnames array",
4624 4625                  devnames_walk_init, devnames_walk_step, devnames_walk_fini },
4625 4626          { "minornode", "given a devinfo node, walk minor nodes",
4626 4627                  minornode_walk_init, minornode_walk_step, NULL },
4627 4628          { "softstate",
4628 4629                  "given an i_ddi_soft_state*, list all in-use driver stateps",
4629 4630                  soft_state_walk_init, soft_state_walk_step,
4630 4631                  NULL, NULL },
4631 4632          { "softstate_all",
4632 4633                  "given an i_ddi_soft_state*, list all driver stateps",
4633 4634                  soft_state_walk_init, soft_state_all_walk_step,
4634 4635                  NULL, NULL },
4635 4636          { "devinfo_fmc",
4636 4637                  "walk a fault management handle cache active list",
4637 4638                  devinfo_fmc_walk_init, devinfo_fmc_walk_step, NULL },
4638 4639  
4639 4640          /* from group.c */
4640 4641          { "group", "walk all elements of a group",
4641 4642                  group_walk_init, group_walk_step, NULL },
4642 4643  
4643 4644          /* from irm.c */
4644 4645          { "irmpools", "walk global list of interrupt pools",
4645 4646              irmpools_walk_init, list_walk_step, list_walk_fini },
4646 4647          { "irmreqs", "walk list of interrupt requests in an interrupt pool",
4647 4648              irmreqs_walk_init, list_walk_step, list_walk_fini },
4648 4649  
4649 4650          /* from kmem.c */
4650 4651          { "allocdby", "given a thread, walk its allocated bufctls",
4651 4652                  allocdby_walk_init, allocdby_walk_step, allocdby_walk_fini },
4652 4653          { "bufctl", "walk a kmem cache's bufctls",
4653 4654                  bufctl_walk_init, kmem_walk_step, kmem_walk_fini },
4654 4655          { "bufctl_history", "walk the available history of a bufctl",
4655 4656                  bufctl_history_walk_init, bufctl_history_walk_step,
4656 4657                  bufctl_history_walk_fini },
4657 4658          { "freedby", "given a thread, walk its freed bufctls",
4658 4659                  freedby_walk_init, allocdby_walk_step, allocdby_walk_fini },
4659 4660          { "freectl", "walk a kmem cache's free bufctls",
4660 4661                  freectl_walk_init, kmem_walk_step, kmem_walk_fini },
4661 4662          { "freectl_constructed", "walk a kmem cache's constructed free bufctls",
4662 4663                  freectl_constructed_walk_init, kmem_walk_step, kmem_walk_fini },
4663 4664          { "freemem", "walk a kmem cache's free memory",
4664 4665                  freemem_walk_init, kmem_walk_step, kmem_walk_fini },
4665 4666          { "freemem_constructed", "walk a kmem cache's constructed free memory",
4666 4667                  freemem_constructed_walk_init, kmem_walk_step, kmem_walk_fini },
4667 4668          { "kmem", "walk a kmem cache",
4668 4669                  kmem_walk_init, kmem_walk_step, kmem_walk_fini },
4669 4670          { "kmem_cpu_cache", "given a kmem cache, walk its per-CPU caches",
4670 4671                  kmem_cpu_cache_walk_init, kmem_cpu_cache_walk_step, NULL },
4671 4672          { "kmem_hash", "given a kmem cache, walk its allocated hash table",
4672 4673                  kmem_hash_walk_init, kmem_hash_walk_step, kmem_hash_walk_fini },
4673 4674          { "kmem_log", "walk the kmem transaction log",
4674 4675                  kmem_log_walk_init, kmem_log_walk_step, kmem_log_walk_fini },
4675 4676          { "kmem_slab", "given a kmem cache, walk its slabs",
4676 4677                  kmem_slab_walk_init, combined_walk_step, combined_walk_fini },
4677 4678          { "kmem_slab_partial",
4678 4679              "given a kmem cache, walk its partially allocated slabs (min 1)",
4679 4680                  kmem_slab_walk_partial_init, combined_walk_step,
4680 4681                  combined_walk_fini },
4681 4682          { "vmem", "walk vmem structures in pre-fix, depth-first order",
4682 4683                  vmem_walk_init, vmem_walk_step, vmem_walk_fini },
4683 4684          { "vmem_alloc", "given a vmem_t, walk its allocated vmem_segs",
4684 4685                  vmem_alloc_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4685 4686          { "vmem_free", "given a vmem_t, walk its free vmem_segs",
4686 4687                  vmem_free_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4687 4688          { "vmem_postfix", "walk vmem structures in post-fix, depth-first order",
4688 4689                  vmem_walk_init, vmem_postfix_walk_step, vmem_walk_fini },
4689 4690          { "vmem_seg", "given a vmem_t, walk all of its vmem_segs",
4690 4691                  vmem_seg_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4691 4692          { "vmem_span", "given a vmem_t, walk its spanning vmem_segs",
4692 4693                  vmem_span_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4693 4694  
4694 4695          /* from ldi.c */
4695 4696          { "ldi_handle", "walk the layered driver handle hash",
4696 4697                  ldi_handle_walk_init, ldi_handle_walk_step, NULL },
4697 4698          { "ldi_ident", "walk the layered driver identifier hash",
4698 4699                  ldi_ident_walk_init, ldi_ident_walk_step, NULL },
4699 4700  
4700 4701          /* from leaky.c + leaky_subr.c */
4701 4702          { "leak", "given a leaked bufctl or vmem_seg, find leaks w/ same "
4702 4703              "stack trace",
4703 4704                  leaky_walk_init, leaky_walk_step, leaky_walk_fini },
4704 4705          { "leakbuf", "given a leaked bufctl or vmem_seg, walk buffers for "
4705 4706              "leaks w/ same stack trace",
4706 4707                  leaky_walk_init, leaky_buf_walk_step, leaky_walk_fini },
4707 4708  
4708 4709          /* from lgrp.c */
4709 4710          { "lgrp_cpulist", "walk CPUs in a given lgroup",
4710 4711                  lgrp_cpulist_walk_init, lgrp_cpulist_walk_step, NULL },
4711 4712          { "lgrptbl", "walk lgroup table",
4712 4713                  lgrp_walk_init, lgrp_walk_step, NULL },
4713 4714          { "lgrp_parents", "walk up lgroup lineage from given lgroup",
4714 4715                  lgrp_parents_walk_init, lgrp_parents_walk_step, NULL },
4715 4716          { "lgrp_rsrc_mem", "walk lgroup memory resources of given lgroup",
4716 4717                  lgrp_rsrc_mem_walk_init, lgrp_set_walk_step, NULL },
4717 4718          { "lgrp_rsrc_cpu", "walk lgroup CPU resources of given lgroup",
4718 4719                  lgrp_rsrc_cpu_walk_init, lgrp_set_walk_step, NULL },
4719 4720  
4720 4721          /* from list.c */
4721 4722          { LIST_WALK_NAME, LIST_WALK_DESC,
4722 4723                  list_walk_init, list_walk_step, list_walk_fini },
4723 4724  
4724 4725          /* from mdi.c */
4725 4726          { "mdipi_client_list", "Walker for mdi_pathinfo pi_client_link",
4726 4727                  mdi_pi_client_link_walk_init,
4727 4728                  mdi_pi_client_link_walk_step,
4728 4729                  mdi_pi_client_link_walk_fini },
4729 4730          { "mdipi_phci_list", "Walker for mdi_pathinfo pi_phci_link",
4730 4731                  mdi_pi_phci_link_walk_init,
4731 4732                  mdi_pi_phci_link_walk_step,
4732 4733                  mdi_pi_phci_link_walk_fini },
4733 4734          { "mdiphci_list", "Walker for mdi_phci ph_next link",
4734 4735                  mdi_phci_ph_next_walk_init,
4735 4736                  mdi_phci_ph_next_walk_step,
4736 4737                  mdi_phci_ph_next_walk_fini },
4737 4738  
4738 4739          /* from memory.c */
4739 4740          { "allpages", "walk all pages, including free pages",
4740 4741                  allpages_walk_init, allpages_walk_step, allpages_walk_fini },
4741 4742          { "anon", "given an amp, list allocated anon structures",
4742 4743                  anon_walk_init, anon_walk_step, anon_walk_fini,
4743 4744                  ANON_WALK_ALLOC },
4744 4745          { "anon_all", "given an amp, list contents of all anon slots",
4745 4746                  anon_walk_init, anon_walk_step, anon_walk_fini,
4746 4747                  ANON_WALK_ALL },
4747 4748          { "memlist", "walk specified memlist",
4748 4749                  NULL, memlist_walk_step, NULL },
4749 4750          { "page", "walk all pages, or those from the specified vnode",
4750 4751                  page_walk_init, page_walk_step, page_walk_fini },
4751 4752          { "seg", "given an as, list of segments",
4752 4753                  seg_walk_init, avl_walk_step, avl_walk_fini },
4753 4754          { "segvn_anon",
4754 4755                  "given a struct segvn_data, list allocated anon structures",
4755 4756                  segvn_anon_walk_init, anon_walk_step, anon_walk_fini,
4756 4757                  ANON_WALK_ALLOC },
4757 4758          { "segvn_anon_all",
4758 4759                  "given a struct segvn_data, list contents of all anon slots",
4759 4760                  segvn_anon_walk_init, anon_walk_step, anon_walk_fini,
4760 4761                  ANON_WALK_ALL },
4761 4762          { "segvn_pages",
4762 4763                  "given a struct segvn_data, list resident pages in "
4763 4764                  "offset order",
4764 4765                  segvn_pages_walk_init, segvn_pages_walk_step,
4765 4766                  segvn_pages_walk_fini, SEGVN_PAGES_RESIDENT },
4766 4767          { "segvn_pages_all",
4767 4768                  "for each offset in a struct segvn_data, give page_t pointer "
4768 4769                  "(if resident), or NULL.",
4769 4770                  segvn_pages_walk_init, segvn_pages_walk_step,
4770 4771                  segvn_pages_walk_fini, SEGVN_PAGES_ALL },
4771 4772          { "swapinfo", "walk swapinfo structures",
4772 4773                  swap_walk_init, swap_walk_step, NULL },
4773 4774  
4774 4775          /* from mmd.c */
4775 4776          { "pattr", "walk pattr_t structures", pattr_walk_init,
4776 4777                  mmdq_walk_step, mmdq_walk_fini },
4777 4778          { "pdesc", "walk pdesc_t structures",
4778 4779                  pdesc_walk_init, mmdq_walk_step, mmdq_walk_fini },
4779 4780          { "pdesc_slab", "walk pdesc_slab_t structures",
4780 4781                  pdesc_slab_walk_init, mmdq_walk_step, mmdq_walk_fini },
4781 4782  
4782 4783          /* from modhash.c */
4783 4784          { "modhash", "walk list of mod_hash structures", modhash_walk_init,
4784 4785                  modhash_walk_step, NULL },
4785 4786          { "modent", "walk list of entries in a given mod_hash",
4786 4787                  modent_walk_init, modent_walk_step, modent_walk_fini },
4787 4788          { "modchain", "walk list of entries in a given mod_hash_entry",
4788 4789                  NULL, modchain_walk_step, NULL },
4789 4790  
4790 4791          /* from net.c */
4791 4792          { "icmp", "walk ICMP control structures using MI for all stacks",
4792 4793                  mi_payload_walk_init, mi_payload_walk_step, NULL,
4793 4794                  &mi_icmp_arg },
4794 4795          { "mi", "given a MI_O, walk the MI",
4795 4796                  mi_walk_init, mi_walk_step, mi_walk_fini, NULL },
4796 4797          { "sonode", "given a sonode, walk its children",
4797 4798                  sonode_walk_init, sonode_walk_step, sonode_walk_fini, NULL },
4798 4799          { "icmp_stacks", "walk all the icmp_stack_t",
4799 4800                  icmp_stacks_walk_init, icmp_stacks_walk_step, NULL },
4800 4801          { "tcp_stacks", "walk all the tcp_stack_t",
4801 4802                  tcp_stacks_walk_init, tcp_stacks_walk_step, NULL },
4802 4803          { "udp_stacks", "walk all the udp_stack_t",
4803 4804                  udp_stacks_walk_init, udp_stacks_walk_step, NULL },
4804 4805  
4805 4806          /* from netstack.c */
4806 4807          { "netstack", "walk a list of kernel netstacks",
4807 4808                  netstack_walk_init, netstack_walk_step, NULL },
4808 4809  
4809 4810          /* from nvpair.c */
4810 4811          { NVPAIR_WALKER_NAME, NVPAIR_WALKER_DESCR,
4811 4812                  nvpair_walk_init, nvpair_walk_step, NULL },
4812 4813  
4813 4814          /* from pci.c */
4814 4815          { "pcie_bus", "walk all pcie_bus_t's", pcie_bus_walk_init,
4815 4816                  pcie_bus_walk_step, NULL },
4816 4817  
4817 4818          /* from rctl.c */
4818 4819          { "rctl_dict_list", "walk all rctl_dict_entry_t's from rctl_lists",
4819 4820                  rctl_dict_walk_init, rctl_dict_walk_step, NULL },
4820 4821          { "rctl_set", "given a rctl_set, walk all rctls", rctl_set_walk_init,
4821 4822                  rctl_set_walk_step, NULL },
4822 4823          { "rctl_val", "given a rctl_t, walk all rctl_val entries associated",
4823 4824                  rctl_val_walk_init, rctl_val_walk_step },
4824 4825  
4825 4826          /* from sobj.c */
4826 4827          { "blocked", "walk threads blocked on a given sobj",
4827 4828                  blocked_walk_init, blocked_walk_step, NULL },
4828 4829          { "wchan", "given a wchan, list of blocked threads",
4829 4830                  wchan_walk_init, wchan_walk_step, wchan_walk_fini },
4830 4831  
4831 4832          /* from stream.c */
4832 4833          { "b_cont", "walk mblk_t list using b_cont",
4833 4834                  mblk_walk_init, b_cont_step, mblk_walk_fini },
4834 4835          { "b_next", "walk mblk_t list using b_next",
4835 4836                  mblk_walk_init, b_next_step, mblk_walk_fini },
4836 4837          { "qlink", "walk queue_t list using q_link",
4837 4838                  queue_walk_init, queue_link_step, queue_walk_fini },
4838 4839          { "qnext", "walk queue_t list using q_next",
4839 4840                  queue_walk_init, queue_next_step, queue_walk_fini },
4840 4841          { "strftblk", "given a dblk_t, walk STREAMS flow trace event list",
4841 4842                  strftblk_walk_init, strftblk_step, strftblk_walk_fini },
4842 4843          { "readq", "walk read queue side of stdata",
4843 4844                  str_walk_init, strr_walk_step, str_walk_fini },
4844 4845          { "writeq", "walk write queue side of stdata",
4845 4846                  str_walk_init, strw_walk_step, str_walk_fini },
4846 4847  
4847 4848          /* from taskq.c */
4848 4849          { "taskq_thread", "given a taskq_t, list all of its threads",
4849 4850                  taskq_thread_walk_init,
4850 4851                  taskq_thread_walk_step,
4851 4852                  taskq_thread_walk_fini },
4852 4853          { "taskq_entry", "given a taskq_t*, list all taskq_ent_t in the list",
4853 4854                  taskq_ent_walk_init, taskq_ent_walk_step, NULL },
4854 4855  
4855 4856          /* from thread.c */
4856 4857          { "deathrow", "walk threads on both lwp_ and thread_deathrow",
4857 4858                  deathrow_walk_init, deathrow_walk_step, NULL },
4858 4859          { "cpu_dispq", "given a cpu_t, walk threads in dispatcher queues",
4859 4860                  cpu_dispq_walk_init, dispq_walk_step, dispq_walk_fini },
4860 4861          { "cpupart_dispq",
4861 4862                  "given a cpupart_t, walk threads in dispatcher queues",
4862 4863                  cpupart_dispq_walk_init, dispq_walk_step, dispq_walk_fini },
4863 4864          { "lwp_deathrow", "walk lwp_deathrow",
4864 4865                  lwp_deathrow_walk_init, deathrow_walk_step, NULL },
4865 4866          { "thread", "global or per-process kthread_t structures",
4866 4867                  thread_walk_init, thread_walk_step, thread_walk_fini },
4867 4868          { "thread_deathrow", "walk threads on thread_deathrow",
4868 4869                  thread_deathrow_walk_init, deathrow_walk_step, NULL },
4869 4870  
4870 4871          /* from tsd.c */
4871 4872          { "tsd", "walk list of thread-specific data",
4872 4873                  tsd_walk_init, tsd_walk_step, tsd_walk_fini },
4873 4874  
4874 4875          /* from tsol.c */
4875 4876          { "tnrh", "walk remote host cache structures",
4876 4877              tnrh_walk_init, tnrh_walk_step, tnrh_walk_fini },
4877 4878          { "tnrhtp", "walk remote host template structures",
4878 4879              tnrhtp_walk_init, tnrhtp_walk_step, tnrhtp_walk_fini },
4879 4880  
4880 4881          /*
4881 4882           * typegraph does not work under kmdb, as it requires too much memory
4882 4883           * for its internal data structures.
4883 4884           */
4884 4885  #ifndef _KMDB
4885 4886          /* from typegraph.c */
4886 4887          { "typeconflict", "walk buffers with conflicting type inferences",
4887 4888                  typegraph_walk_init, typeconflict_walk_step },
4888 4889          { "typeunknown", "walk buffers with unknown types",
4889 4890                  typegraph_walk_init, typeunknown_walk_step },
4890 4891  #endif
4891 4892  
4892 4893          /* from vfs.c */
4893 4894          { "vfs", "walk file system list",
4894 4895                  vfs_walk_init, vfs_walk_step },
4895 4896  
4896 4897          /* from zone.c */
4897 4898          { "zone", "walk a list of kernel zones",
4898 4899                  zone_walk_init, zone_walk_step, NULL },
4899 4900          { "zsd", "walk list of zsd entries for a zone",
4900 4901                  zsd_walk_init, zsd_walk_step, NULL },
4901 4902  
4902 4903          { NULL }
4903 4904  };
4904 4905  
4905 4906  static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
4906 4907  
4907 4908  /*ARGSUSED*/
4908 4909  static void
4909 4910  genunix_statechange_cb(void *ignored)
4910 4911  {
4911 4912          /*
4912 4913           * Force ::findleaks and ::stacks to let go any cached state.
4913 4914           */
4914 4915          leaky_cleanup(1);
4915 4916          stacks_cleanup(1);
4916 4917  
4917 4918          kmem_statechange();     /* notify kmem */
4918 4919  }
4919 4920  
4920 4921  const mdb_modinfo_t *
4921 4922  _mdb_init(void)
4922 4923  {
4923 4924          kmem_init();
4924 4925  
4925 4926          (void) mdb_callback_add(MDB_CALLBACK_STCHG,
4926 4927              genunix_statechange_cb, NULL);
4927 4928  
4928 4929  #ifndef _KMDB
4929 4930          gcore_init();
4930 4931  #endif
4931 4932  
4932 4933          return (&modinfo);
4933 4934  }
4934 4935  
4935 4936  void
4936 4937  _mdb_fini(void)
4937 4938  {
4938 4939          leaky_cleanup(1);
4939 4940          stacks_cleanup(1);
4940 4941  }
  
    | 
      ↓ open down ↓ | 
    633 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX