1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <mdb/mdb_modapi.h>
  26 #include <mdb/mdb_ks.h>
  27 
  28 #include <sys/types.h>
  29 #include <sys/systm.h>
  30 #include <sys/door.h>
  31 #include <sys/file.h>
  32 #include <sys/mount.h>
  33 #include <sys/proc.h>
  34 #include <sys/procfs.h>
  35 #include <sys/proc/prdata.h>
  36 #include <sys/stat.h>
  37 #include <sys/vfs.h>
  38 #include <sys/vnode.h>
  39 #include <sys/fs/snode.h>
  40 #include <sys/fs/fifonode.h>
  41 #include <sys/fs/namenode.h>
  42 #include <sys/socket.h>
  43 #include <sys/stropts.h>
  44 #include <sys/socketvar.h>
  45 #include <sys/strsubr.h>
  46 #include <sys/un.h>
  47 #include <fs/sockfs/socktpi_impl.h>
  48 #include <inet/ipclassifier.h>
  49 #include <inet/ip_if.h>
  50 #include <inet/sctp/sctp_impl.h>
  51 #include <inet/sctp/sctp_addr.h>
  52 
  53 int
  54 vfs_walk_init(mdb_walk_state_t *wsp)
  55 {
  56         if (wsp->walk_addr == NULL &&
  57             mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) {
  58                 mdb_warn("failed to read 'rootvfs'");
  59                 return (WALK_ERR);
  60         }
  61 
  62         wsp->walk_data = (void *)wsp->walk_addr;
  63         return (WALK_NEXT);
  64 }
  65 
  66 int
  67 vfs_walk_step(mdb_walk_state_t *wsp)
  68 {
  69         vfs_t vfs;
  70         int status;
  71 
  72         if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) {
  73                 mdb_warn("failed to read vfs_t at %p", wsp->walk_addr);
  74                 return (WALK_DONE);
  75         }
  76 
  77         status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata);
  78 
  79         if (vfs.vfs_next == wsp->walk_data)
  80                 return (WALK_DONE);
  81 
  82         wsp->walk_addr = (uintptr_t)vfs.vfs_next;
  83 
  84         return (status);
  85 }
  86 
  87 /*
  88  * Utility routine to read in a filesystem name given a vfs pointer.  If
  89  * no vfssw entry for the vfs is available (as is the case with some pseudo-
  90  * filesystems), we check against some known problem fs's: doorfs and
  91  * portfs.  If that fails, we try to guess the filesystem name using
  92  * symbol names.  fsname should be a buffer of size _ST_FSTYPSZ.
  93  */
  94 static int
  95 read_fsname(uintptr_t vfsp, char *fsname)
  96 {
  97         vfs_t vfs;
  98         struct vfssw vfssw_entry;
  99         GElf_Sym vfssw_sym, test_sym;
 100         char testname[MDB_SYM_NAMLEN];
 101 
 102         if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) {
 103                 mdb_warn("failed to read vfs %p", vfsp);
 104                 return (-1);
 105         }
 106 
 107         if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) {
 108                 mdb_warn("failed to find vfssw");
 109                 return (-1);
 110         }
 111 
 112         /*
 113          * vfssw is an array; we need vfssw[vfs.vfs_fstype].
 114          */
 115         if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry),
 116             vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype))
 117             == -1) {
 118                 mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype);
 119                 return (-1);
 120         }
 121 
 122         if (vfs.vfs_fstype != 0) {
 123                 if (mdb_readstr(fsname, _ST_FSTYPSZ,
 124                     (uintptr_t)vfssw_entry.vsw_name) == -1) {
 125                         mdb_warn("failed to find fs name %p",
 126                             vfssw_entry.vsw_name);
 127                         return (-1);
 128                 }
 129                 return (0);
 130         }
 131 
 132         /*
 133          * Do precise detection for certain filesystem types that we
 134          * know do not appear in vfssw[], and that we depend upon in other
 135          * parts of the code: doorfs and portfs.
 136          */
 137         if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) {
 138                 if (test_sym.st_value == vfsp) {
 139                         strcpy(fsname, "doorfs");
 140                         return (0);
 141                 }
 142         }
 143         if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) {
 144                 if (test_sym.st_value == vfsp) {
 145                         strcpy(fsname, "portfs");
 146                         return (0);
 147                 }
 148         }
 149 
 150         /*
 151          * Heuristic detection for other filesystems that don't have a
 152          * vfssw[] entry.  These tend to be named <fsname>_vfs, so we do a
 153          * lookup_by_addr and see if we find a symbol of that name.
 154          */
 155         if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname),
 156             &test_sym) != -1) {
 157                 if ((strlen(testname) > 4) &&
 158                     (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) {
 159                         testname[strlen(testname) - 4] = '\0';
 160                         strncpy(fsname, testname, _ST_FSTYPSZ);
 161                         return (0);
 162                 }
 163         }
 164 
 165         mdb_warn("unknown filesystem type for vfs %p", vfsp);
 166         return (-1);
 167 }
 168 
 169 /*
 170  * Column widths for mount point display in ::fsinfo output.
 171  */
 172 #ifdef _LP64
 173 #define FSINFO_MNTLEN   48
 174 #else
 175 #define FSINFO_MNTLEN   56
 176 #endif
 177 
 178 /* ARGSUSED */
 179 int
 180 fsinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 181 {
 182         vfs_t vfs;
 183         int len;
 184         int opt_v = 0;
 185         char buf[MAXPATHLEN];
 186         char fsname[_ST_FSTYPSZ];
 187         mntopt_t *mntopts;
 188         size_t size;
 189         int i;
 190         int first = 1;
 191         char opt[MAX_MNTOPT_STR];
 192         uintptr_t global_zone;
 193 
 194         if (!(flags & DCMD_ADDRSPEC)) {
 195                 if (mdb_walk_dcmd("vfs", "fsinfo", argc, argv) == -1) {
 196                         mdb_warn("failed to walk file system list");
 197                         return (DCMD_ERR);
 198                 }
 199                 return (DCMD_OK);
 200         }
 201 
 202         if (mdb_getopts(argc, argv,
 203             'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
 204                 return (DCMD_USAGE);
 205 
 206         if (DCMD_HDRSPEC(flags))
 207                 mdb_printf("%<u>%?s %-15s %s%</u>\n",
 208                     "VFSP", "FS", "MOUNT");
 209 
 210         if (mdb_vread(&vfs, sizeof (vfs), addr) == -1) {
 211                 mdb_warn("failed to read vfs_t %p", addr);
 212                 return (DCMD_ERR);
 213         }
 214 
 215         if ((len = mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf,
 216             sizeof (buf))) <= 0)
 217                 strcpy(buf, "??");
 218 
 219         else if (!opt_v && (len >= FSINFO_MNTLEN))
 220                 /*
 221                  * In normal mode, we truncate the path to keep the output
 222                  * clean.  In -v mode, we just print the full path.
 223                  */
 224                 strcpy(&buf[FSINFO_MNTLEN - 4], "...");
 225 
 226         if (read_fsname(addr, fsname) == -1)
 227                 return (DCMD_ERR);
 228 
 229         mdb_printf("%0?p %-15s %s\n", addr, fsname, buf);
 230 
 231         if (!opt_v)
 232                 return (DCMD_OK);
 233 
 234         /*
 235          * Print 'resource' string; this shows what we're mounted upon.
 236          */
 237         if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf,
 238             MAXPATHLEN) <= 0)
 239                 strcpy(buf, "??");
 240 
 241         mdb_printf("%?s %s\n", "R:", buf);
 242 
 243         /*
 244          * Print mount options array; it sucks to be a mimic, but we copy
 245          * the same logic as in mntvnops.c for adding zone= tags, and we
 246          * don't bother with the obsolete dev= option.
 247          */
 248         size = vfs.vfs_mntopts.mo_count * sizeof (mntopt_t);
 249         mntopts = mdb_alloc(size, UM_SLEEP | UM_GC);
 250 
 251         if (mdb_vread(mntopts, size,
 252             (uintptr_t)vfs.vfs_mntopts.mo_list) == -1) {
 253                 mdb_warn("failed to read mntopts %p", vfs.vfs_mntopts.mo_list);
 254                 return (DCMD_ERR);
 255         }
 256 
 257         for (i = 0; i < vfs.vfs_mntopts.mo_count; i++) {
 258                 if (mntopts[i].mo_flags & MO_SET) {
 259                         if (mdb_readstr(opt, sizeof (opt),
 260                             (uintptr_t)mntopts[i].mo_name) == -1) {
 261                                 mdb_warn("failed to read mntopt name %p",
 262                                     mntopts[i].mo_name);
 263                                 return (DCMD_ERR);
 264                         }
 265                         if (first) {
 266                                 mdb_printf("%?s ", "O:");
 267                                 first = 0;
 268                         } else {
 269                                 mdb_printf(",");
 270                         }
 271                         mdb_printf("%s", opt);
 272                         if (mntopts[i].mo_flags & MO_HASVALUE) {
 273                                 if (mdb_readstr(opt, sizeof (opt),
 274                                     (uintptr_t)mntopts[i].mo_arg) == -1) {
 275                                         mdb_warn("failed to read mntopt "
 276                                             "value %p", mntopts[i].mo_arg);
 277                                         return (DCMD_ERR);
 278                                 }
 279                                 mdb_printf("=%s", opt);
 280                         }
 281                 }
 282         }
 283 
 284         if (mdb_readvar(&global_zone, "global_zone") == -1) {
 285                 mdb_warn("failed to locate global_zone");
 286                 return (DCMD_ERR);
 287         }
 288 
 289         if ((vfs.vfs_zone != NULL) &&
 290             ((uintptr_t)vfs.vfs_zone != global_zone)) {
 291                 zone_t z;
 292 
 293                 if (mdb_vread(&z, sizeof (z), (uintptr_t)vfs.vfs_zone) == -1) {
 294                         mdb_warn("failed to read zone");
 295                         return (DCMD_ERR);
 296                 }
 297                 /*
 298                  * zone names are much shorter than MAX_MNTOPT_STR
 299                  */
 300                 if (mdb_readstr(opt, sizeof (opt),
 301                     (uintptr_t)z.zone_name) == -1) {
 302                         mdb_warn("failed to read zone name");
 303                         return (DCMD_ERR);
 304                 }
 305                 if (first) {
 306                         mdb_printf("%?s ", "O:");
 307                 } else {
 308                         mdb_printf(",");
 309                 }
 310                 mdb_printf("zone=%s", opt);
 311         }
 312         return (DCMD_OK);
 313 }
 314 
 315 
 316 #define REALVP_DONE     0
 317 #define REALVP_ERR      1
 318 #define REALVP_CONTINUE 2
 319 
 320 static int
 321 next_realvp(uintptr_t invp, struct vnode *outvn, uintptr_t *outvp)
 322 {
 323         char fsname[_ST_FSTYPSZ];
 324 
 325         *outvp = invp;
 326         if (mdb_vread(outvn, sizeof (struct vnode), invp) == -1) {
 327                 mdb_warn("failed to read vnode at %p", invp);
 328                 return (REALVP_ERR);
 329         }
 330 
 331         if (read_fsname((uintptr_t)outvn->v_vfsp, fsname) == -1)
 332                 return (REALVP_ERR);
 333 
 334         /*
 335          * We know how to do 'realvp' for as many filesystems as possible;
 336          * for all other filesystems, we assume that the vp we are given
 337          * is the realvp.  In the kernel, a realvp operation will sometimes
 338          * dig through multiple layers.  Here, we only fetch the pointer
 339          * to the next layer down.  This allows dcmds to print out the
 340          * various layers.
 341          */
 342         if (strcmp(fsname, "fifofs") == 0) {
 343                 fifonode_t fn;
 344                 if (mdb_vread(&fn, sizeof (fn),
 345                     (uintptr_t)outvn->v_data) == -1) {
 346                         mdb_warn("failed to read fifonode");
 347                         return (REALVP_ERR);
 348                 }
 349                 *outvp = (uintptr_t)fn.fn_realvp;
 350 
 351         } else if (strcmp(fsname, "namefs") == 0) {
 352                 struct namenode nn;
 353                 if (mdb_vread(&nn, sizeof (nn),
 354                     (uintptr_t)outvn->v_data) == -1) {
 355                         mdb_warn("failed to read namenode");
 356                         return (REALVP_ERR);
 357                 }
 358                 *outvp = (uintptr_t)nn.nm_filevp;
 359 
 360         } else if (outvn->v_type == VSOCK && outvn->v_stream != NULL) {
 361                 struct stdata stream;
 362 
 363                 /*
 364                  * Sockets have a strange and different layering scheme; we
 365                  * hop over into the sockfs vnode (accessible via the stream
 366                  * head) if possible.
 367                  */
 368                 if (mdb_vread(&stream, sizeof (stream),
 369                     (uintptr_t)outvn->v_stream) == -1) {
 370                         mdb_warn("failed to read stream data");
 371                         return (REALVP_ERR);
 372                 }
 373                 *outvp = (uintptr_t)stream.sd_vnode;
 374         }
 375 
 376         if (*outvp == invp || *outvp == NULL)
 377                 return (REALVP_DONE);
 378 
 379         return (REALVP_CONTINUE);
 380 }
 381 
 382 static void
 383 pfiles_print_addr(struct sockaddr *addr)
 384 {
 385         struct sockaddr_in *s_in;
 386         struct sockaddr_un *s_un;
 387         struct sockaddr_in6 *s_in6;
 388         in_port_t port;
 389 
 390         switch (addr->sa_family) {
 391         case AF_INET:
 392                 /* LINTED: alignment */
 393                 s_in = (struct sockaddr_in *)addr;
 394                 mdb_nhconvert(&port, &s_in->sin_port, sizeof (port));
 395                 mdb_printf("AF_INET %I %d ", s_in->sin_addr.s_addr, port);
 396                 break;
 397 
 398         case AF_INET6:
 399                 /* LINTED: alignment */
 400                 s_in6 = (struct sockaddr_in6 *)addr;
 401                 mdb_nhconvert(&port, &s_in6->sin6_port, sizeof (port));
 402                 mdb_printf("AF_INET6 %N %d ", &(s_in6->sin6_addr), port);
 403                 break;
 404 
 405         case AF_UNIX:
 406                 s_un = (struct sockaddr_un *)addr;
 407                 mdb_printf("AF_UNIX %s ", s_un->sun_path);
 408                 break;
 409         default:
 410                 mdb_printf("AF_?? (%d) ", addr->sa_family);
 411                 break;
 412         }
 413 }
 414 
 415 static int
 416 pfiles_get_sonode(vnode_t *v_sock, struct sonode *sonode)
 417 {
 418         if (mdb_vread(sonode, sizeof (struct sonode),
 419             (uintptr_t)v_sock->v_data) == -1) {
 420                 mdb_warn("failed to read sonode");
 421                 return (-1);
 422         }
 423 
 424         return (0);
 425 }
 426 
 427 static int
 428 pfiles_get_tpi_sonode(vnode_t *v_sock, sotpi_sonode_t *sotpi_sonode)
 429 {
 430 
 431         struct stdata stream;
 432 
 433         if (mdb_vread(&stream, sizeof (stream),
 434             (uintptr_t)v_sock->v_stream) == -1) {
 435                 mdb_warn("failed to read stream data");
 436                 return (-1);
 437         }
 438 
 439         if (mdb_vread(v_sock, sizeof (vnode_t),
 440             (uintptr_t)stream.sd_vnode) == -1) {
 441                 mdb_warn("failed to read stream vnode");
 442                 return (-1);
 443         }
 444 
 445         if (mdb_vread(sotpi_sonode, sizeof (sotpi_sonode_t),
 446             (uintptr_t)v_sock->v_data) == -1) {
 447                 mdb_warn("failed to read sotpi_sonode");
 448                 return (-1);
 449         }
 450 
 451         return (0);
 452 }
 453 
 454 /*
 455  * Do some digging to get a reasonable pathname for this vnode. 'path'
 456  * should point at a buffer of MAXPATHLEN in size.
 457  */
 458 static int
 459 pfiles_dig_pathname(uintptr_t vp, char *path)
 460 {
 461         vnode_t v;
 462 
 463         bzero(path, MAXPATHLEN);
 464 
 465         if (mdb_vread(&v, sizeof (v), vp) == -1) {
 466                 mdb_warn("failed to read vnode");
 467                 return (-1);
 468         }
 469 
 470         if (v.v_path == NULL) {
 471                 /*
 472                  * fifo's and doors are special.   Some have pathnames, and
 473                  * some do not.  And for these, it is pointless to go off to
 474                  * mdb_vnode2path, which is very slow.
 475                  *
 476                  * Event ports never have a pathname.
 477                  */
 478                 if (v.v_type == VFIFO || v.v_type == VDOOR || v.v_type == VPORT)
 479                         return (0);
 480 
 481                 /*
 482                  * For sockets, we won't find a path unless we print the path
 483                  * associated with transport's STREAM device.
 484                  */
 485                 if (v.v_type == VSOCK) {
 486                         struct sonode sonode;
 487                         struct sockparams sockparams;
 488 
 489                         if (pfiles_get_sonode(&v, &sonode) == -1) {
 490                                 return (-1);
 491                         }
 492                         if (mdb_vread(&sockparams, sizeof (sockparams),
 493                             (uintptr_t)sonode.so_sockparams) == -1) {
 494                                 mdb_warn("failed to read sockparams");
 495                                 return (-1);
 496                         }
 497 
 498                         if (!SOCK_IS_NONSTR(&sonode)) {
 499                                 vp = (uintptr_t)
 500                                     sockparams.sp_sdev_info.sd_vnode;
 501                         } else {
 502                                 vp = NULL;
 503                         }
 504                 }
 505         }
 506 
 507 
 508         /*
 509          * mdb_vnode2path will print an error for us as needed, but not
 510          * finding a pathname is not really an error, so we plow on.
 511          */
 512         (void) mdb_vnode2path(vp, path, MAXPATHLEN);
 513 
 514         /*
 515          * A common problem is that device pathnames are prefixed with
 516          * /dev/../devices/.  We just clean those up slightly:
 517          *      /dev/../devices/<mumble> --> /devices/<mumble>
 518          *      /dev/pts/../../devices/<mumble> --> /devices/<mumble>
 519          */
 520         if (strncmp("/dev/../devices/", path, strlen("/dev/../devices/")) == 0)
 521                 strcpy(path, path + 7);
 522 
 523         if (strncmp("/dev/pts/../../devices/", path,
 524             strlen("/dev/pts/../../devices/")) == 0)
 525                 strcpy(path, path + 14);
 526 
 527         return (0);
 528 }
 529 
 530 const struct fs_type {
 531         vtype_t type;
 532         const char *name;
 533 } fs_types[] = {
 534         { VNON,   "NON" },
 535         { VREG,   "REG" },
 536         { VDIR,   "DIR" },
 537         { VBLK,   "BLK" },
 538         { VCHR,   "CHR" },
 539         { VLNK,   "LNK" },
 540         { VFIFO,  "FIFO" },
 541         { VDOOR,  "DOOR" },
 542         { VPROC,  "PROC" },
 543         { VSOCK,  "SOCK" },
 544         { VPORT,  "PORT" },
 545         { VBAD,   "BAD" }
 546 };
 547 
 548 #define NUM_FS_TYPES (sizeof (fs_types) / sizeof (struct fs_type))
 549 
 550 struct pfiles_cbdata {
 551         int opt_p;
 552         int fd;
 553 };
 554 
 555 #define list_d2l(a, obj) ((list_node_t *)(((char *)obj) + (a)->list_offset))
 556 #define list_object(a, node) ((void *)(((char *)node) - (a)->list_offset))
 557 
 558 /*
 559  * SCTP interface for geting the first source address of a sctp_t.
 560  */
 561 int
 562 sctp_getsockaddr(sctp_t *sctp, struct sockaddr *addr)
 563 {
 564         int                     err = -1;
 565         int                     i;
 566         int                     l;
 567         sctp_saddr_ipif_t       *pobj;
 568         sctp_saddr_ipif_t       obj;
 569         size_t                  added = 0;
 570         sin6_t                  *sin6;
 571         sin_t                   *sin4;
 572         int                     scanned = 0;
 573         boolean_t               skip_lback = B_FALSE;
 574         conn_t                  *connp = sctp->sctp_connp;
 575 
 576         addr->sa_family = connp->conn_family;
 577         if (sctp->sctp_nsaddrs == 0)
 578                 goto done;
 579 
 580         /*
 581          * Skip loopback addresses for non-loopback assoc.
 582          */
 583         if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback) {
 584                 skip_lback = B_TRUE;
 585         }
 586 
 587         for (i = 0; i < SCTP_IPIF_HASH; i++) {
 588                 if (sctp->sctp_saddrs[i].ipif_count == 0)
 589                         continue;
 590 
 591                 pobj = list_object(&sctp->sctp_saddrs[i].sctp_ipif_list,
 592                     sctp->sctp_saddrs[i].sctp_ipif_list.list_head.list_next);
 593                 if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t),
 594                     (uintptr_t)pobj) == -1) {
 595                         mdb_warn("failed to read sctp_saddr_ipif_t");
 596                         return (err);
 597                 }
 598 
 599                 for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
 600                         sctp_ipif_t     ipif;
 601                         in6_addr_t      laddr;
 602                         list_node_t     *pnode;
 603                         list_node_t     node;
 604 
 605                         if (mdb_vread(&ipif, sizeof (sctp_ipif_t),
 606                             (uintptr_t)obj.saddr_ipifp) == -1) {
 607                                 mdb_warn("failed to read sctp_ipif_t");
 608                                 return (err);
 609                         }
 610                         laddr = ipif.sctp_ipif_saddr;
 611 
 612                         scanned++;
 613                         if ((ipif.sctp_ipif_state == SCTP_IPIFS_CONDEMNED) ||
 614                             SCTP_DONT_SRC(&obj) ||
 615                             (ipif.sctp_ipif_ill->sctp_ill_flags &
 616                             PHYI_LOOPBACK) && skip_lback) {
 617                                 if (scanned >= sctp->sctp_nsaddrs)
 618                                         goto done;
 619 
 620                                 /* LINTED: alignment */
 621                                 pnode = list_d2l(&sctp->sctp_saddrs[i].
 622                                     sctp_ipif_list, pobj);
 623                                 if (mdb_vread(&node, sizeof (list_node_t),
 624                                     (uintptr_t)pnode) == -1) {
 625                                         mdb_warn("failed to read list_node_t");
 626                                         return (err);
 627                                 }
 628                                 pobj = list_object(&sctp->sctp_saddrs[i].
 629                                     sctp_ipif_list, node.list_next);
 630                                 if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t),
 631                                     (uintptr_t)pobj) == -1) {
 632                                         mdb_warn("failed to read "
 633                                             "sctp_saddr_ipif_t");
 634                                         return (err);
 635                                 }
 636                                 continue;
 637                         }
 638 
 639                         switch (connp->conn_family) {
 640                         case AF_INET:
 641                                 /* LINTED: alignment */
 642                                 sin4 = (sin_t *)addr;
 643                                 if ((sctp->sctp_state <= SCTPS_LISTEN) &&
 644                                     sctp->sctp_bound_to_all) {
 645                                         sin4->sin_addr.s_addr = INADDR_ANY;
 646                                         sin4->sin_port = connp->conn_lport;
 647                                 } else {
 648                                         sin4 += added;
 649                                         sin4->sin_family = AF_INET;
 650                                         sin4->sin_port = connp->conn_lport;
 651                                         IN6_V4MAPPED_TO_INADDR(&laddr,
 652                                             &sin4->sin_addr);
 653                                 }
 654                                 break;
 655 
 656                         case AF_INET6:
 657                                 /* LINTED: alignment */
 658                                 sin6 = (sin6_t *)addr;
 659                                 if ((sctp->sctp_state <= SCTPS_LISTEN) &&
 660                                     sctp->sctp_bound_to_all) {
 661                                         bzero(&sin6->sin6_addr,
 662                                             sizeof (sin6->sin6_addr));
 663                                         sin6->sin6_port = connp->conn_lport;
 664                                 } else {
 665                                         sin6 += added;
 666                                         sin6->sin6_family = AF_INET6;
 667                                         sin6->sin6_port = connp->conn_lport;
 668                                         sin6->sin6_addr = laddr;
 669                                 }
 670                                 sin6->sin6_flowinfo = connp->conn_flowinfo;
 671                                 sin6->sin6_scope_id = 0;
 672                                 sin6->__sin6_src_id = 0;
 673                                 break;
 674                         }
 675                         added++;
 676                         if (added >= 1) {
 677                                 err = 0;
 678                                 goto done;
 679                         }
 680                         if (scanned >= sctp->sctp_nsaddrs)
 681                                 goto done;
 682 
 683                         /* LINTED: alignment */
 684                         pnode = list_d2l(&sctp->sctp_saddrs[i].sctp_ipif_list,
 685                             pobj);
 686                         if (mdb_vread(&node, sizeof (list_node_t),
 687                             (uintptr_t)pnode) == -1) {
 688                                 mdb_warn("failed to read list_node_t");
 689                                 return (err);
 690                         }
 691                         pobj = list_object(&sctp->sctp_saddrs[i].
 692                             sctp_ipif_list, node.list_next);
 693                         if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t),
 694                             (uintptr_t)pobj) == -1) {
 695                                 mdb_warn("failed to read sctp_saddr_ipif_t");
 696                                 return (err);
 697                         }
 698                 }
 699         }
 700 done:
 701         return (err);
 702 }
 703 
 704 /*
 705  * SCTP interface for geting the primary peer address of a sctp_t.
 706  */
 707 static int
 708 sctp_getpeeraddr(sctp_t *sctp, struct sockaddr *addr)
 709 {
 710         struct sockaddr_in      *sin4;
 711         struct sockaddr_in6     *sin6;
 712         sctp_faddr_t            sctp_primary;
 713         in6_addr_t              faddr;
 714         conn_t                  *connp = sctp->sctp_connp;
 715 
 716         if (sctp->sctp_faddrs == NULL)
 717                 return (-1);
 718 
 719         addr->sa_family = connp->conn_family;
 720         if (mdb_vread(&sctp_primary, sizeof (sctp_faddr_t),
 721             (uintptr_t)sctp->sctp_primary) == -1) {
 722                 mdb_warn("failed to read sctp primary faddr");
 723                 return (-1);
 724         }
 725         faddr = sctp_primary.sf_faddr;
 726 
 727         switch (connp->conn_family) {
 728         case AF_INET:
 729                 /* LINTED: alignment */
 730                 sin4 = (struct sockaddr_in *)addr;
 731                 IN6_V4MAPPED_TO_INADDR(&faddr, &sin4->sin_addr);
 732                 sin4->sin_port = connp->conn_fport;
 733                 sin4->sin_family = AF_INET;
 734                 break;
 735 
 736         case AF_INET6:
 737                 /* LINTED: alignment */
 738                 sin6 = (struct sockaddr_in6 *)addr;
 739                 sin6->sin6_addr = faddr;
 740                 sin6->sin6_port = connp->conn_fport;
 741                 sin6->sin6_family = AF_INET6;
 742                 sin6->sin6_flowinfo = 0;
 743                 sin6->sin6_scope_id = 0;
 744                 sin6->__sin6_src_id = 0;
 745                 break;
 746         }
 747 
 748         return (0);
 749 }
 750 
 751 static int
 752 tpi_sock_print(sotpi_sonode_t *sotpi_sonode)
 753 {
 754         if (sotpi_sonode->st_info.sti_laddr_valid == 1) {
 755                 struct sockaddr *laddr =
 756                     mdb_alloc(sotpi_sonode->st_info.sti_laddr_len, UM_SLEEP);
 757                 if (mdb_vread(laddr, sotpi_sonode->st_info.sti_laddr_len,
 758                     (uintptr_t)sotpi_sonode->st_info.sti_laddr_sa) == -1) {
 759                         mdb_warn("failed to read sotpi_sonode socket addr");
 760                         return (-1);
 761                 }
 762 
 763                 mdb_printf("socket: ");
 764                 pfiles_print_addr(laddr);
 765         }
 766 
 767         if (sotpi_sonode->st_info.sti_faddr_valid == 1) {
 768                 struct sockaddr *faddr =
 769                     mdb_alloc(sotpi_sonode->st_info.sti_faddr_len, UM_SLEEP);
 770                 if (mdb_vread(faddr, sotpi_sonode->st_info.sti_faddr_len,
 771                     (uintptr_t)sotpi_sonode->st_info.sti_faddr_sa) == -1) {
 772                         mdb_warn("failed to read sotpi_sonode remote addr");
 773                         return (-1);
 774                 }
 775 
 776                 mdb_printf("remote: ");
 777                 pfiles_print_addr(faddr);
 778         }
 779 
 780         return (0);
 781 }
 782 
 783 static int
 784 tcpip_sock_print(struct sonode *socknode)
 785 {
 786         switch (socknode->so_family) {
 787         case AF_INET:
 788         {
 789                 conn_t conn_t;
 790                 in_port_t port;
 791 
 792                 if (mdb_vread(&conn_t, sizeof (conn_t),
 793                     (uintptr_t)socknode->so_proto_handle) == -1) {
 794                         mdb_warn("failed to read conn_t V4");
 795                         return (-1);
 796                 }
 797 
 798                 mdb_printf("socket: ");
 799                 mdb_nhconvert(&port, &conn_t.conn_lport, sizeof (port));
 800                 mdb_printf("AF_INET %I %d ", conn_t.conn_laddr_v4, port);
 801 
 802                 /*
 803                  * If this is a listening socket, we don't print
 804                  * the remote address.
 805                  */
 806                 if (IPCL_IS_TCP(&conn_t) && IPCL_IS_BOUND(&conn_t) == 0 ||
 807                     IPCL_IS_UDP(&conn_t) && IPCL_IS_CONNECTED(&conn_t)) {
 808                         mdb_printf("remote: ");
 809                         mdb_nhconvert(&port, &conn_t.conn_fport, sizeof (port));
 810                         mdb_printf("AF_INET %I %d ", conn_t.conn_faddr_v4,
 811                             port);
 812                 }
 813 
 814                 break;
 815         }
 816 
 817         case AF_INET6:
 818         {
 819                 conn_t conn_t;
 820                 in_port_t port;
 821 
 822                 if (mdb_vread(&conn_t, sizeof (conn_t),
 823                     (uintptr_t)socknode->so_proto_handle) == -1) {
 824                         mdb_warn("failed to read conn_t V6");
 825                         return (-1);
 826                 }
 827 
 828                 mdb_printf("socket: ");
 829                 mdb_nhconvert(&port, &conn_t.conn_lport, sizeof (port));
 830                 mdb_printf("AF_INET6 %N %d ", &conn_t.conn_laddr_v4, port);
 831 
 832                 /*
 833                  * If this is a listening socket, we don't print
 834                  * the remote address.
 835                  */
 836                 if (IPCL_IS_TCP(&conn_t) && IPCL_IS_BOUND(&conn_t) == 0 ||
 837                     IPCL_IS_UDP(&conn_t) && IPCL_IS_CONNECTED(&conn_t)) {
 838                         mdb_printf("remote: ");
 839                         mdb_nhconvert(&port, &conn_t.conn_fport, sizeof (port));
 840                         mdb_printf("AF_INET6 %N %d ", &conn_t.conn_faddr_v6,
 841                             port);
 842                 }
 843 
 844                 break;
 845         }
 846 
 847         default:
 848                 mdb_printf("AF_?? (%d)", socknode->so_family);
 849                 break;
 850         }
 851 
 852         return (0);
 853 }
 854 
 855 static int
 856 sctp_sock_print(struct sonode *socknode)
 857 {
 858         sctp_t sctp_t;
 859         conn_t conns;
 860 
 861         struct sockaddr *laddr = mdb_alloc(sizeof (struct sockaddr), UM_SLEEP);
 862         struct sockaddr *faddr = mdb_alloc(sizeof (struct sockaddr), UM_SLEEP);
 863 
 864         if (mdb_vread(&sctp_t, sizeof (sctp_t),
 865             (uintptr_t)socknode->so_proto_handle) == -1) {
 866                 mdb_warn("failed to read sctp_t");
 867                 return (-1);
 868         }
 869 
 870         if (mdb_vread(&conns, sizeof (conn_t),
 871             (uintptr_t)sctp_t.sctp_connp) == -1) {
 872                 mdb_warn("failed to read conn_t at %p",
 873                     (uintptr_t)sctp_t.sctp_connp);
 874                 return (-1);
 875         }
 876         sctp_t.sctp_connp = &conns;
 877 
 878         if (sctp_getsockaddr(&sctp_t, laddr) == 0) {
 879                 mdb_printf("socket:");
 880                 pfiles_print_addr(laddr);
 881         }
 882         if (sctp_getpeeraddr(&sctp_t, faddr) == 0) {
 883                 mdb_printf("remote:");
 884                 pfiles_print_addr(faddr);
 885         }
 886 
 887         return (0);
 888 }
 889 
 890 /* ARGSUSED */
 891 static int
 892 sdp_sock_print(struct sonode *socknode)
 893 {
 894         return (0);
 895 }
 896 
 897 struct sock_print {
 898         int     family;
 899         int     type;
 900         int     pro;
 901         int     (*print)(struct sonode *socknode);
 902 } sock_prints[] = {
 903         { 2,    2,      0,      tcpip_sock_print },     /* /dev/tcp     */
 904         { 2,    2,      6,      tcpip_sock_print },     /* /dev/tcp     */
 905         { 26,   2,      0,      tcpip_sock_print },     /* /dev/tcp6    */
 906         { 26,   2,      6,      tcpip_sock_print },     /* /dev/tcp6    */
 907         { 2,    1,      0,      tcpip_sock_print },     /* /dev/udp     */
 908         { 2,    1,      17,     tcpip_sock_print },     /* /dev/udp     */
 909         { 26,   1,      0,      tcpip_sock_print },     /* /dev/udp6    */
 910         { 26,   1,      17,     tcpip_sock_print },     /* /dev/udp6    */
 911         { 2,    4,      0,      tcpip_sock_print },     /* /dev/rawip   */
 912         { 26,   4,      0,      tcpip_sock_print },     /* /dev/rawip6  */
 913         { 2,    2,      132,    sctp_sock_print },      /* /dev/sctp    */
 914         { 26,   2,      132,    sctp_sock_print },      /* /dev/sctp6   */
 915         { 2,    6,      132,    sctp_sock_print },      /* /dev/sctp    */
 916         { 26,   6,      132,    sctp_sock_print },      /* /dev/sctp6   */
 917         { 24,   4,      0,      tcpip_sock_print },     /* /dev/rts     */
 918         { 2,    2,      257,    sdp_sock_print },       /* /dev/sdp     */
 919         { 26,   2,      257,    sdp_sock_print },       /* /dev/sdp     */
 920 };
 921 
 922 #define NUM_SOCK_PRINTS                                         \
 923         (sizeof (sock_prints) / sizeof (struct sock_print))
 924 
 925 static int
 926 pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
 927 {
 928         vnode_t v, layer_vn;
 929         int myfd = cb->fd;
 930         const char *type;
 931         char path[MAXPATHLEN];
 932         uintptr_t top_vnodep, realvpp;
 933         char fsname[_ST_FSTYPSZ];
 934         int err, i;
 935 
 936         cb->fd++;
 937 
 938         if (addr == NULL) {
 939                 return (WALK_NEXT);
 940         }
 941 
 942         top_vnodep = realvpp = (uintptr_t)f->f_vnode;
 943 
 944         if (mdb_vread(&v, sizeof (v), realvpp) == -1) {
 945                 mdb_warn("failed to read vnode");
 946                 return (DCMD_ERR);
 947         }
 948 
 949         type = "?";
 950         for (i = 0; i < NUM_FS_TYPES; i++) {
 951                 if (fs_types[i].type == v.v_type) {
 952                         type = fs_types[i].name;
 953                         break;
 954                 }
 955         }
 956 
 957         do {
 958                 uintptr_t next_realvpp;
 959 
 960                 err = next_realvp(realvpp, &layer_vn, &next_realvpp);
 961                 if (next_realvpp != NULL)
 962                         realvpp = next_realvpp;
 963 
 964         } while (err == REALVP_CONTINUE);
 965 
 966         if (err == REALVP_ERR) {
 967                 mdb_warn("failed to do realvp() for %p", realvpp);
 968                 return (DCMD_ERR);
 969         }
 970 
 971         if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1)
 972                 return (DCMD_ERR);
 973 
 974         mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep);
 975 
 976         if (cb->opt_p) {
 977                 if (pfiles_dig_pathname(top_vnodep, path) == -1)
 978                         return (DCMD_ERR);
 979 
 980                 mdb_printf("%s\n", path);
 981                 return (DCMD_OK);
 982         }
 983 
 984         /*
 985          * Sockets generally don't have interesting pathnames; we only
 986          * show those in the '-p' view.
 987          */
 988         path[0] = '\0';
 989         if (v.v_type != VSOCK) {
 990                 if (pfiles_dig_pathname(top_vnodep, path) == -1)
 991                         return (DCMD_ERR);
 992         }
 993         mdb_printf("%s%s", path, path[0] == '\0' ? "" : " ");
 994 
 995         switch (v.v_type) {
 996         case VDOOR:
 997         {
 998                 door_node_t doornode;
 999                 proc_t pr;
1000 
1001                 if (mdb_vread(&doornode, sizeof (doornode),
1002                     (uintptr_t)layer_vn.v_data) == -1) {
1003                         mdb_warn("failed to read door_node");
1004                         return (DCMD_ERR);
1005                 }
1006 
1007                 if (mdb_vread(&pr, sizeof (pr),
1008                     (uintptr_t)doornode.door_target) == -1) {
1009                         mdb_warn("failed to read door server process %p",
1010                             doornode.door_target);
1011                         return (DCMD_ERR);
1012                 }
1013                 mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm,
1014                     doornode.door_target);
1015                 break;
1016         }
1017 
1018         case VSOCK:
1019         {
1020                 vnode_t v_sock;
1021                 struct sonode so;
1022 
1023                 if (mdb_vread(&v_sock, sizeof (v_sock), realvpp) == -1) {
1024                         mdb_warn("failed to read socket vnode");
1025                         return (DCMD_ERR);
1026                 }
1027 
1028                 /*
1029                  * Sockets can be non-stream or stream, they have to be dealed
1030                  * with differently.
1031                  */
1032                 if (v_sock.v_stream == NULL) {
1033                         if (pfiles_get_sonode(&v_sock, &so) == -1)
1034                                 return (DCMD_ERR);
1035 
1036                         /* Pick the proper methods. */
1037                         for (i = 0; i <= NUM_SOCK_PRINTS; i++) {
1038                                 if ((sock_prints[i].family == so.so_family &&
1039                                     sock_prints[i].type == so.so_type &&
1040                                     sock_prints[i].pro == so.so_protocol) ||
1041                                     (sock_prints[i].family == so.so_family &&
1042                                     sock_prints[i].type == so.so_type &&
1043                                     so.so_type == SOCK_RAW)) {
1044                                         if ((*sock_prints[i].print)(&so) == -1)
1045                                                 return (DCMD_ERR);
1046                                 }
1047                         }
1048                 } else {
1049                         sotpi_sonode_t sotpi_sonode;
1050 
1051                         if (pfiles_get_sonode(&v_sock, &so) == -1)
1052                                 return (DCMD_ERR);
1053 
1054                         /*
1055                          * If the socket is a fallback socket, read its related
1056                          * information separately; otherwise, read it as a whole
1057                          * tpi socket.
1058                          */
1059                         if (so.so_state & SS_FALLBACK_COMP) {
1060                                 sotpi_sonode.st_sonode = so;
1061 
1062                                 if (mdb_vread(&(sotpi_sonode.st_info),
1063                                     sizeof (sotpi_info_t),
1064                                     (uintptr_t)so.so_priv) == -1)
1065                                         return (DCMD_ERR);
1066                         } else {
1067                                 if (pfiles_get_tpi_sonode(&v_sock,
1068                                     &sotpi_sonode) == -1)
1069                                         return (DCMD_ERR);
1070                         }
1071 
1072                         if (tpi_sock_print(&sotpi_sonode) == -1)
1073                                 return (DCMD_ERR);
1074                 }
1075 
1076                 break;
1077         }
1078 
1079         case VPORT:
1080                 mdb_printf("[event port (port=%p)]", v.v_data);
1081                 break;
1082 
1083         case VPROC:
1084         {
1085                 prnode_t prnode;
1086                 prcommon_t prcommon;
1087 
1088                 if (mdb_vread(&prnode, sizeof (prnode),
1089                     (uintptr_t)layer_vn.v_data) == -1) {
1090                         mdb_warn("failed to read prnode");
1091                         return (DCMD_ERR);
1092                 }
1093 
1094                 if (mdb_vread(&prcommon, sizeof (prcommon),
1095                     (uintptr_t)prnode.pr_common) == -1) {
1096                         mdb_warn("failed to read prcommon %p",
1097                             prnode.pr_common);
1098                         return (DCMD_ERR);
1099                 }
1100 
1101                 mdb_printf("(proc=%p)", prcommon.prc_proc);
1102                 break;
1103         }
1104 
1105         default:
1106                 break;
1107         }
1108 
1109         mdb_printf("\n");
1110 
1111         return (WALK_NEXT);
1112 }
1113 
1114 static int
1115 file_t_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
1116 {
1117         int myfd = cb->fd;
1118 
1119         cb->fd++;
1120 
1121         if (addr == NULL) {
1122                 return (WALK_NEXT);
1123         }
1124 
1125         /*
1126          * We really need 20 digits to print a 64-bit offset_t, but this
1127          * is exceedingly rare, so we cheat and assume a column width of 10
1128          * digits, in order to fit everything cleanly into 80 columns.
1129          */
1130         mdb_printf("%?0p %4d %8x %?0p %10lld %?0p %4d\n",
1131             addr, myfd, f->f_flag, f->f_vnode, f->f_offset, f->f_cred,
1132             f->f_count);
1133 
1134         return (WALK_NEXT);
1135 }
1136 
1137 int
1138 pfiles(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1139 {
1140         int opt_f = 0;
1141 
1142         struct pfiles_cbdata cb;
1143 
1144         bzero(&cb, sizeof (cb));
1145 
1146         if (!(flags & DCMD_ADDRSPEC))
1147                 return (DCMD_USAGE);
1148 
1149         if (mdb_getopts(argc, argv,
1150             'p', MDB_OPT_SETBITS, TRUE, &cb.opt_p,
1151             'f', MDB_OPT_SETBITS, TRUE, &opt_f, NULL) != argc)
1152                 return (DCMD_USAGE);
1153 
1154         if (opt_f) {
1155                 mdb_printf("%<u>%?s %4s %8s %?s %10s %?s %4s%</u>\n", "FILE",
1156                     "FD", "FLAG", "VNODE", "OFFSET", "CRED", "CNT");
1157                 if (mdb_pwalk("allfile", (mdb_walk_cb_t)file_t_callback, &cb,
1158                     addr) == -1) {
1159                         mdb_warn("failed to walk 'allfile'");
1160                         return (DCMD_ERR);
1161                 }
1162         } else {
1163                 mdb_printf("%<u>%-4s %4s %?s ", "FD", "TYPE", "VNODE");
1164                 if (cb.opt_p)
1165                         mdb_printf("PATH");
1166                 else
1167                         mdb_printf("INFO");
1168                 mdb_printf("%</u>\n");
1169 
1170                 if (mdb_pwalk("allfile", (mdb_walk_cb_t)pfile_callback, &cb,
1171                     addr) == -1) {
1172                         mdb_warn("failed to walk 'allfile'");
1173                         return (DCMD_ERR);
1174                 }
1175         }
1176 
1177 
1178         return (DCMD_OK);
1179 }
1180 
1181 void
1182 pfiles_help(void)
1183 {
1184         mdb_printf(
1185             "Given the address of a process, print information about files\n"
1186             "which the process has open.  By default, this includes decoded\n"
1187             "information about the file depending on file and filesystem type\n"
1188             "\n"
1189             "\t-p\tPathnames; omit decoded information.  Only display "
1190             "pathnames\n"
1191             "\t-f\tfile_t view; show the file_t structure corresponding to "
1192             "the fd\n");
1193 }