1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 /*
  12  * Copyright (c) 2013 by Delphix. All rights reserved.
  13  */
  14 
  15 /*
  16  * This file implements the mdb ::gcore command.  The command relies on the
  17  * libproc Pgcore function to actually generate the core file but we provide
  18  * our own ops vector to populate data required by Pgcore.  The ops vector
  19  * function implementations simulate the functionality implemented by procfs.
  20  * The data provided by some of the ops vector functions is not complete
  21  * (missing data is documented in function headers) but there is enough
  22  * information to generate a core file that can be loaded into mdb.
  23  *
  24  * Currently only x86 is supported. ISA-dependent functions are implemented
  25  * in gcore_isadep.c.
  26  */
  27 
  28 #ifndef _KMDB
  29 
  30 /*
  31  * The kernel has its own definition of exit which has a different signature
  32  * than the user space definition.  This seems to be the standard way to deal
  33  * with this.
  34  */
  35 #define exit kern_exit
  36 
  37 #include <mdb/mdb_modapi.h>
  38 #include <mdb/mdb_param.h>
  39 #include <mdb/mdb_ks.h>
  40 #include <mdb/mdb_ctf.h>
  41 #include <mdb/mdb_debug.h>
  42 #include <mdb/mdb_gcore.h>
  43 
  44 #include <sys/class.h>
  45 #include <sys/cpuvar.h>
  46 #include <sys/proc.h>
  47 #include <sys/lgrp.h>
  48 #include <sys/pool.h>
  49 #include <sys/project.h>
  50 #include <sys/regset.h>
  51 #include <sys/schedctl.h>
  52 #include <sys/session.h>
  53 #include <sys/syscall.h>
  54 #include <sys/task.h>
  55 #include <sys/var.h>
  56 #include <sys/privregs.h>
  57 #include <sys/fault.h>
  58 #include <sys/sysmacros.h>
  59 #include <sys/wait.h>
  60 #include <vm/seg.h>
  61 #include <vm/vpage.h>
  62 #include <fs/proc/prdata.h>
  63 
  64 #undef exit
  65 
  66 #include <stdio.h>
  67 #include <stdbool.h>
  68 #include <string.h>
  69 #include <libproc.h>
  70 
  71 #include "avl.h"
  72 
  73 #ifdef _LP64
  74 #define LSPAN(type)     (P2ROUNDUP(sizeof (type), 16))
  75 #else
  76 #define LSPAN(type)     (P2ROUNDUP(sizeof (type), 8))
  77 #endif
  78 
  79 #define vpgtob(n)       ((n) * sizeof (struct vpage))
  80 
  81 /* Macros to invoke gcore seg operations */
  82 #define GSOP_INIT(_gs)          (_gs)->gs_ops->gsop_init((_gs))
  83 #define GSOP_FINI(_gs)          (_gs)->gs_ops->gsop_fini((_gs))
  84 #define GSOP_INCORE(_gs, _addr, _eaddr) \
  85         (_gs)->gs_ops->gsop_incore((_gs), (_addr), (_eaddr))
  86 #define GSOP_GETPROT(_gs, _addr)        \
  87         (_gs)->gs_ops->gsop_getprot((_gs), (_addr))
  88 #define GSOP_GETOFFSET(_gs, _addr)      \
  89         (_gs)->gs_ops->gsop_getoffset((_gs), (_addr))
  90 #define GSOP_GETTYPE(_gs, _addr)        \
  91         (_gs)->gs_ops->gsop_gettype((_gs), (_addr))
  92 #define GSOP_NAME(_gs, _name, _size)    \
  93         (_gs)->gs_ops->gsop_name((_gs), (_name), (_size))
  94 #define GSOP_NORESERVE(_gs)             \
  95         (_gs)->gs_ops->gsop_noreserve((_gs))
  96 
  97 #ifdef GCORE_DEBUG
  98 #define dprintf(...)    mdb_printf(__VA_ARGS__)
  99 #else
 100 #define dprintf(...)
 101 #endif
 102 
 103 /* Callback function type for processing lwp entries */
 104 typedef int (*lwp_callback_t)(mdb_proc_t *, lwpent_t *, void *);
 105 
 106 /* Private data */
 107 static uintptr_t gcore_segvn_ops;
 108 static priv_impl_info_t prinfo;
 109 static sclass_t *gcore_sclass;
 110 static uintptr_t gcore_kas;
 111 static boolean_t gcore_initialized = B_FALSE;
 112 
 113 typedef int (*gsop_init_t)(gcore_seg_t *);
 114 typedef void (*gsop_fini_t)(gcore_seg_t *);
 115 typedef u_offset_t (*gsop_incore_t)(gcore_seg_t *, u_offset_t, u_offset_t);
 116 typedef uint_t (*gsop_getprot_t)(gcore_seg_t *, u_offset_t);
 117 typedef int (*gsop_getoffset_t)(gcore_seg_t *, u_offset_t);
 118 typedef void (*gsop_name_t)(gcore_seg_t *, char *name, size_t size);
 119 typedef int (*gsop_gettype_t)(gcore_seg_t *, u_offset_t);
 120 typedef boolean_t (*gsop_noreserve_t)(gcore_seg_t *);
 121 
 122 typedef struct gcore_segops {
 123         gsop_init_t             gsop_init;
 124         gsop_fini_t             gsop_fini;
 125         gsop_incore_t           gsop_incore;
 126         gsop_getprot_t          gsop_getprot;
 127         gsop_getoffset_t        gsop_getoffset;
 128         gsop_name_t             gsop_name;
 129         gsop_gettype_t          gsop_gettype;
 130         gsop_noreserve_t        gsop_noreserve;
 131 } gcore_segops_t;
 132 
 133 static void map_list_free(prmap_node_t *);
 134 static uintptr_t gcore_prchoose(mdb_proc_t *);
 135 
 136 /*
 137  * Segvn ops
 138  */
 139 static int gsvn_init(gcore_seg_t *);
 140 static void gsvn_fini(gcore_seg_t *);
 141 static u_offset_t gsvn_incore(gcore_seg_t *, u_offset_t, u_offset_t);
 142 static uint_t gsvn_getprot(gcore_seg_t *, u_offset_t);
 143 static int gsvn_getoffset(gcore_seg_t *, u_offset_t);
 144 static void gsvn_name(gcore_seg_t *, char *, size_t);
 145 static int gsvn_gettype(gcore_seg_t *, u_offset_t);
 146 static boolean_t gsvn_noreserve(gcore_seg_t *);
 147 
 148 static gcore_segops_t gsvn_ops = {
 149         .gsop_init              = gsvn_init,
 150         .gsop_fini              = gsvn_fini,
 151         .gsop_incore            = gsvn_incore,
 152         .gsop_getprot           = gsvn_getprot,
 153         .gsop_getoffset         = gsvn_getoffset,
 154         .gsop_name              = gsvn_name,
 155         .gsop_gettype           = gsvn_gettype,
 156         .gsop_noreserve         = gsvn_noreserve
 157 };
 158 
 159 static int
 160 gsvn_init(gcore_seg_t *gs)
 161 {
 162         mdb_seg_t               *seg = gs->gs_seg;
 163         mdb_segvn_data_t        *svd = NULL;
 164         struct vpage            *vpage = NULL;
 165         size_t                  nvpage = 0;
 166 
 167         if (seg->s_data != NULL) {
 168                 svd = mdb_alloc(sizeof (*svd), UM_SLEEP);
 169                 if (mdb_ctf_vread(svd, "segvn_data_t", "mdb_segvn_data_t",
 170                     seg->s_data, 0) == -1) {
 171                         goto error;
 172                 }
 173 
 174                 if (svd->pageprot != 0) {
 175                         nvpage = seg_pages(seg);
 176                         dprintf("vpage count: %d\n", nvpage);
 177 
 178                         vpage = mdb_alloc(vpgtob(nvpage), UM_SLEEP);
 179                         if (mdb_vread(vpage, vpgtob(nvpage),
 180                             (uintptr_t)svd->vpage) != vpgtob(nvpage)) {
 181                                 mdb_warn("Failed to read vpages from %p\n",
 182                                     svd->vpage);
 183                                 goto error;
 184                         }
 185 
 186                         svd->vpage = vpage;
 187                 } else {
 188                         svd->vpage = NULL;
 189                 }
 190                 gs->gs_data = svd;
 191         } else {
 192                 gs->gs_data = NULL;
 193         }
 194 
 195         return (0);
 196 
 197 error:
 198         mdb_free(vpage, vpgtob(nvpage));
 199         mdb_free(svd, sizeof (*svd));
 200         return (-1);
 201 }
 202 
 203 /*ARGSUSED*/
 204 static int
 205 gsvn_getoffset(gcore_seg_t *gs, u_offset_t addr)
 206 {
 207         mdb_segvn_data_t        *svd = gs->gs_data;
 208         mdb_seg_t               *seg = gs->gs_seg;
 209 
 210         return (svd->offset + (uintptr_t)(addr - seg->s_base));
 211 }
 212 
 213 static void
 214 gsvn_name(gcore_seg_t *gs, char *name, size_t size)
 215 {
 216         mdb_segvn_data_t        *svd = gs->gs_data;
 217 
 218         name[0] = '\0';
 219         if (svd->vp != 0) {
 220                 mdb_seg_t       *seg = gs->gs_seg;
 221                 mdb_as_t        as;
 222                 mdb_proc_t      p;
 223                 mdb_vnode_t     vn;
 224 
 225                 if (mdb_ctf_vread(&vn, "vnode_t", "mdb_vnode_t", svd->vp, 0)
 226                     == -1) {
 227                         return;
 228                 }
 229 
 230                 if (mdb_ctf_vread(&as, "struct as", "mdb_as_t", seg->s_as, 0)
 231                     == -1) {
 232                         return;
 233                 }
 234 
 235                 if (mdb_ctf_vread(&p, "proc_t", "mdb_proc_t", as.a_proc, 0)
 236                     == -1) {
 237                         return;
 238                 }
 239 
 240                 if (vn.v_type == VREG && svd->vp == p.p_exec) {
 241                         (void) strncpy(name, "a.out", size);
 242                 }
 243 
 244                 /*
 245                  * procfs has more logic here to construct a name using
 246                  * vfs/vnode identifiers but didn't seem worthwhile to add
 247                  * here.
 248                  */
 249         }
 250 }
 251 
 252 /*ARGSUSED*/
 253 static int
 254 gsvn_gettype(gcore_seg_t *gs, u_offset_t addr)
 255 {
 256         return (0);
 257 }
 258 
 259 static void
 260 gsvn_fini(gcore_seg_t *gs)
 261 {
 262         mdb_segvn_data_t        *svd = gs->gs_data;
 263 
 264         if (svd != NULL) {
 265                 if (svd->vpage != NULL) {
 266                         size_t nvpage = seg_pages(gs->gs_seg);
 267 
 268                         mdb_free(svd->vpage, vpgtob(nvpage));
 269                 }
 270                 mdb_free(svd, sizeof (*svd));
 271         }
 272 }
 273 
 274 static boolean_t
 275 gsvn_noreserve(gcore_seg_t *gs)
 276 {
 277         mdb_segvn_data_t        *svd = gs->gs_data;
 278 
 279         if (svd == NULL) {
 280                 return (B_FALSE);
 281         }
 282 
 283         if (svd->flags & MAP_NORESERVE) {
 284                 mdb_vnode_t vn;
 285 
 286                 if (svd->vp == 0) {
 287                         return (B_TRUE);
 288                 }
 289 
 290                 if (mdb_ctf_vread(&vn, "vnode_t", "mdb_vnode_t",
 291                     svd->vp, 0) == -1) {
 292                         return (B_FALSE);
 293                 }
 294 
 295                 if (vn.v_type != VREG) {
 296                         return (B_TRUE);
 297                 }
 298         }
 299 
 300         return (B_FALSE);
 301 }
 302 
 303 static uintptr_t
 304 gcore_anon_get_ptr(uintptr_t ah_addr, ulong_t an_idx)
 305 {
 306         mdb_anon_hdr_t  ah;
 307         uintptr_t       anon_addr;
 308         uintptr_t       anon_ptr;
 309 
 310         if (mdb_ctf_vread(&ah, "struct anon_hdr", "mdb_anon_hdr_t", ah_addr,
 311             0) == -1) {
 312                 return (0);
 313         }
 314 
 315         /*
 316          * Single level case.
 317          */
 318         if ((ah.size <= ANON_CHUNK_SIZE) || (ah.flags & ANON_ALLOC_FORCE)) {
 319                 anon_addr = ah.array_chunk + (sizeof (anon_ptr) * an_idx);
 320                 if (mdb_vread(&anon_ptr, sizeof (anon_ptr), anon_addr) !=
 321                     sizeof (anon_ptr)) {
 322                         mdb_warn("Failed to read anon_ptr from %p (1 level)\n",
 323                             anon_addr);
 324                         return (0);
 325                 }
 326 
 327                 return (anon_ptr & ANON_PTRMASK);
 328         }
 329 
 330         /*
 331          * 2 level case.
 332          */
 333         anon_addr = ah.array_chunk + (sizeof (anon_ptr) *
 334             (an_idx >> ANON_CHUNK_SHIFT));
 335 
 336         if (mdb_vread(&anon_ptr, sizeof (anon_ptr), anon_addr) !=
 337             sizeof (anon_ptr)) {
 338                 mdb_warn("Failed to read anon_ptr from %p (2a level)\n",
 339                     anon_addr);
 340                 return (0);
 341         }
 342 
 343         if (anon_ptr == 0) {
 344                 return (0);
 345         }
 346 
 347         anon_addr = anon_ptr + (sizeof (anon_ptr) *
 348             (an_idx & ANON_CHUNK_OFF));
 349         if (mdb_vread(&anon_ptr, sizeof (anon_ptr), anon_addr) !=
 350             sizeof (anon_ptr)) {
 351                 mdb_warn("Failed to read anon_ptr from %p (2b level)\n",
 352                     anon_addr);
 353                 return (0);
 354         }
 355 
 356         return (anon_ptr & ANON_PTRMASK);
 357 }
 358 
 359 static void
 360 gcore_anon_get(uintptr_t ahp, ulong_t an_index, uintptr_t *vp, u_offset_t *off)
 361 {
 362         mdb_anon_t      anon;
 363         uintptr_t       ap;
 364 
 365         ap = gcore_anon_get_ptr(ahp, an_index);
 366         if (ap != 0) {
 367                 if (mdb_ctf_vread(&anon, "struct anon", "mdb_anon_t", ap, 0) ==
 368                     -1) {
 369                         return;
 370                 }
 371 
 372                 *vp = anon.an_vp;
 373                 *off = anon.an_off;
 374         } else {
 375                 *vp = 0;
 376                 *off = 0;
 377         }
 378 }
 379 
 380 static u_offset_t
 381 gsvn_incore(gcore_seg_t *gs, u_offset_t addr, u_offset_t eaddr)
 382 {
 383         mdb_segvn_data_t        *svd = gs->gs_data;
 384         mdb_seg_t               *seg = gs->gs_seg;
 385         mdb_amp_t               amp;
 386         u_offset_t              offset;
 387         uintptr_t               vp;
 388         size_t                  p, ep;
 389 
 390         if (svd->amp != 0 && mdb_ctf_vread(&amp, "amp_t", "mdb_amp_t", svd->amp,
 391             0) == -1) {
 392                 return (eaddr);
 393         }
 394 
 395         p = seg_page(seg, addr);
 396         ep = seg_page(seg, eaddr);
 397         for (; p < ep; p++, addr += PAGESIZE) {
 398                 /* First check the anon map */
 399                 if (svd->amp != 0) {
 400                         gcore_anon_get(amp.ahp, svd->anon_index + p, &vp,
 401                             &offset);
 402                         if (vp != 0 && mdb_page_lookup(vp, offset) != 0) {
 403                                 break;
 404                         }
 405                 }
 406 
 407                 /* Now check the segment's vnode */
 408                 vp = svd->vp;
 409                 offset = svd->offset + (addr - gs->gs_seg->s_base);
 410                 if (mdb_page_lookup(vp, offset) != 0) {
 411                         break;
 412                 }
 413 
 414                 dprintf("amp: %p vp: %p addr: %p offset: %p not in core!\n",
 415                     svd->amp, svd->vp, addr, offset);
 416         }
 417 
 418         return (addr);
 419 }
 420 
 421 static uint_t
 422 gsvn_getprot(gcore_seg_t *gs, u_offset_t addr)
 423 {
 424         mdb_segvn_data_t        *svd = gs->gs_data;
 425         mdb_seg_t               *seg = gs->gs_seg;
 426 
 427         if (svd->pageprot == 0) {
 428                 return (svd->prot);
 429         }
 430 
 431         dprintf("addr: %p pgno: %p\n", addr, seg_page(seg, addr));
 432         return (VPP_PROT(&svd->vpage[seg_page(seg, addr)]));
 433 }
 434 
 435 /*
 436  * Helper functions for constructing the process address space maps.
 437  */
 438 /*ARGSUSED*/
 439 static int
 440 as_segat_cb(uintptr_t seg_addr, const void *aw_buff, void *arg)
 441 {
 442         as_segat_cbarg_t *as_segat_arg = arg;
 443         mdb_seg_t       seg;
 444 
 445         if (mdb_ctf_vread(&seg, "struct seg", "mdb_seg_t", seg_addr, 0) == -1) {
 446                 return (WALK_ERR);
 447         }
 448 
 449         if (as_segat_arg->addr < seg.s_base) {
 450                 return (WALK_NEXT);
 451         }
 452 
 453         if (as_segat_arg->addr >= seg.s_base + seg.s_size) {
 454                 return (WALK_NEXT);
 455         }
 456 
 457         as_segat_arg->res = seg_addr;
 458         return (WALK_DONE);
 459 }
 460 
 461 /*
 462  * Find a segment containing addr.
 463  */
 464 static uintptr_t
 465 gcore_as_segat(uintptr_t as_addr, uintptr_t addr)
 466 {
 467         as_segat_cbarg_t as_segat_arg;
 468         uintptr_t       segtree_addr;
 469 
 470         as_segat_arg.addr = addr;
 471         as_segat_arg.res = 0;
 472 
 473         segtree_addr = as_addr + mdb_ctf_offsetof_by_name("struct as",
 474             "a_segtree");
 475         (void) avl_walk_mdb(segtree_addr, as_segat_cb, &as_segat_arg);
 476 
 477         return (as_segat_arg.res);
 478 }
 479 
 480 static uintptr_t
 481 gcore_break_seg(mdb_proc_t *p)
 482 {
 483         uintptr_t addr = p->p_brkbase;
 484 
 485         if (p->p_brkbase != 0)
 486                 addr += p->p_brksize - 1;
 487 
 488         return (gcore_as_segat(p->p_as, addr));
 489 }
 490 
 491 static u_offset_t
 492 gcore_vnode_size(uintptr_t vnode_addr)
 493 {
 494         mdb_vnode_t     vnode;
 495         mdb_vnodeops_t  vnodeops;
 496         char            vops_name[128];
 497 
 498         if (mdb_ctf_vread(&vnode, "vnode_t", "mdb_vnode_t", vnode_addr, 0) ==
 499             -1) {
 500                 return (-1);
 501         }
 502 
 503         if (mdb_ctf_vread(&vnodeops, "vnodeops_t", "mdb_vnodeops_t",
 504             vnode.v_op, 0) == -1) {
 505                 return (-1);
 506         }
 507 
 508         if (mdb_readstr(vops_name, sizeof (vops_name), vnodeops.vnop_name) ==
 509             -1) {
 510                 mdb_warn("Failed to read vnop_name from %p\n",
 511                     vnodeops.vnop_name);
 512                 return (-1);
 513         }
 514 
 515         if (strcmp(vops_name, "zfs") == 0) {
 516                 mdb_znode_t     znode;
 517 
 518                 if (mdb_ctf_vread(&znode, "znode_t", "mdb_znode_t",
 519                     vnode.v_data, 0) == -1) {
 520                         return (-1);
 521                 }
 522                 return (znode.z_size);
 523         }
 524 
 525         if (strcmp(vops_name, "tmpfs") == 0) {
 526                 mdb_tmpnode_t   tnode;
 527 
 528                 if (mdb_ctf_vread(&tnode, "struct tmpnode", "mdb_tmpnode_t",
 529                     vnode.v_data, 0) == -1)  {
 530                         return (-1);
 531                 }
 532                 return (tnode.tn_attr.va_size);
 533         }
 534 
 535         /* Unknown file system type. */
 536         mdb_warn("Unknown fs type: %s\n", vops_name);
 537         return (-1);
 538 }
 539 
 540 static uint64_t
 541 gcore_pr_getsegsize(mdb_seg_t *seg)
 542 {
 543         uint64_t size = seg->s_size;
 544 
 545         if (seg->s_ops == gcore_segvn_ops) {
 546                 mdb_segvn_data_t svd;
 547 
 548                 if (mdb_ctf_vread(&svd, "segvn_data_t", "mdb_segvn_data_t",
 549                     seg->s_data, 0) == -1) {
 550                         return (-1);
 551                 }
 552 
 553                 if (svd.vp != 0) {
 554                         u_offset_t fsize;
 555                         u_offset_t offset;
 556 
 557                         fsize = gcore_vnode_size(svd.vp);
 558                         if (fsize == -1) {
 559                                 return (-1);
 560                         }
 561                         offset = svd.offset;
 562 
 563                         if (fsize < offset) {
 564                                 fsize = 0;
 565                         } else {
 566                                 fsize -= offset;
 567                         }
 568 
 569                         fsize = roundup(fsize, PAGESIZE);
 570                 }
 571 
 572                 return (size);
 573         }
 574 
 575         return (size);
 576 }
 577 
 578 /*ARGSUSED*/
 579 static int
 580 gcore_getwatchprot_cb(uintptr_t node_addr, const void *aw_buff, void *arg)
 581 {
 582         getwatchprot_cbarg_t    *cbarg = arg;
 583 
 584         if (mdb_ctf_vread(&cbarg->wp, "struct watched_page",
 585             "mdb_watched_page_t", node_addr, 0) == -1) {
 586                 return (WALK_ERR);
 587         }
 588 
 589         if (cbarg->wp.wp_vaddr == cbarg->wp_vaddr) {
 590                 cbarg->found = B_TRUE;
 591                 return (WALK_DONE);
 592         }
 593 
 594         return (WALK_NEXT);
 595 }
 596 
 597 static void
 598 gcore_getwatchprot(uintptr_t as_addr, u_offset_t addr, uint_t *prot)
 599 {
 600         getwatchprot_cbarg_t    cbarg;
 601         uintptr_t               wp_addr;
 602 
 603         cbarg.wp_vaddr = (uintptr_t)addr & (uintptr_t)PAGEMASK;
 604         cbarg.found = B_FALSE;
 605 
 606         wp_addr = as_addr + mdb_ctf_offsetof_by_name("struct as", "a_wpage");
 607         (void) avl_walk_mdb(wp_addr, gcore_getwatchprot_cb, &cbarg);
 608 
 609         if (cbarg.found) {
 610                 *prot = cbarg.wp.wp_oprot;
 611         }
 612 }
 613 
 614 static u_offset_t
 615 gcore_pr_nextprot(gcore_seg_t *gs, u_offset_t *saddrp, u_offset_t eaddr,
 616     uint_t *protp)
 617 {
 618         uint_t          prot, nprot;
 619         u_offset_t      addr = *saddrp;
 620         uintptr_t       as_addr = gs->gs_seg->s_as;
 621         int             noreserve = 0;
 622 
 623         noreserve = GSOP_NORESERVE(gs);
 624         dprintf("addr: %p noreserve: %d\n", addr, noreserve);
 625 
 626         if (noreserve) {
 627                 addr = GSOP_INCORE(gs, addr, eaddr);
 628                 if (addr == eaddr) {
 629                         prot = 0;
 630                         *saddrp = addr;
 631                         goto out;
 632                 }
 633         }
 634 
 635         prot = GSOP_GETPROT(gs, addr);
 636         gcore_getwatchprot(as_addr, addr, &prot);
 637         *saddrp = addr;
 638 
 639         for (addr += PAGESIZE; addr < eaddr; addr += PAGESIZE) {
 640                 /* Discontinuity */
 641                 if (noreserve && GSOP_INCORE(gs, addr, eaddr) != addr) {
 642                         goto out;
 643                 }
 644 
 645                 nprot = GSOP_GETPROT(gs, addr);
 646                 gcore_getwatchprot(as_addr, addr, &nprot);
 647 
 648                 if (nprot != prot) {
 649                         break;
 650                 }
 651         }
 652 
 653 out:
 654         *protp = prot;
 655         return (addr);
 656 }
 657 
 658 /*
 659  * Get the page protection for the given start address.
 660  *   - saddrp: in - start address
 661  *             out - contains address of first in core page
 662  *   - naddrp: out - address of next in core page that has different protection
 663  *   - eaddr: in - end address
 664  */
 665 static uint_t
 666 gcore_pr_getprot(gcore_seg_t *gs, u_offset_t *saddrp, u_offset_t *naddrp,
 667     u_offset_t eaddr)
 668 {
 669         u_offset_t      naddr;
 670         uint_t          prot;
 671 
 672         dprintf("seg: %p saddr: %p eaddr: %p\n",
 673             gs->gs_seg, *saddrp, eaddr);
 674 
 675         naddr = gcore_pr_nextprot(gs, saddrp, eaddr, &prot);
 676 
 677         dprintf("seg: %p saddr: %p naddr: %p eaddr: %p\n",
 678             gs->gs_seg, *saddrp, naddr, eaddr);
 679 
 680         *naddrp = naddr;
 681         return (prot);
 682 }
 683 
 684 static gcore_seg_t *
 685 gcore_seg_create(mdb_seg_t *seg)
 686 {
 687         gcore_seg_t     *gs;
 688 
 689         gs = mdb_alloc(sizeof (*gs), UM_SLEEP);
 690         gs->gs_seg = seg;
 691         if (seg->s_ops == gcore_segvn_ops) {
 692                 gs->gs_ops = &gsvn_ops;
 693         } else {
 694                 mdb_warn("Unhandled segment type, ops: %p\n", seg->s_ops);
 695                 goto error;
 696         }
 697 
 698         if (GSOP_INIT(gs) != 0) {
 699                 goto error;
 700         }
 701 
 702         return (gs);
 703 
 704 error:
 705         mdb_free(gs, sizeof (*gs));
 706         return (NULL);
 707 }
 708 
 709 static void
 710 gcore_seg_destroy(gcore_seg_t *gs)
 711 {
 712         GSOP_FINI(gs);
 713         mdb_free(gs, sizeof (*gs));
 714 }
 715 
 716 /*ARGSUSED*/
 717 static int
 718 read_maps_cb(uintptr_t seg_addr, const void *aw_buff, void *arg)
 719 {
 720         read_maps_cbarg_t       *cbarg = arg;
 721         mdb_segvn_data_t        svd;
 722         mdb_seg_t               s;
 723         mdb_seg_t               *seg;
 724         uint_t                  prot;
 725         gcore_seg_t             *gs;
 726         uintptr_t               eaddr;
 727         u_offset_t              saddr, baddr;
 728         prmap_node_t            *mnode;
 729         prmap_t                 *mp;
 730 
 731         if (mdb_ctf_vread(&s, "struct seg", "mdb_seg_t", seg_addr, 0) == -1) {
 732                 return (WALK_ERR);
 733         }
 734         seg = &s;
 735         eaddr = seg->s_base + gcore_pr_getsegsize(seg);
 736 
 737         if ((gs = gcore_seg_create(seg)) == NULL) {
 738                 mdb_warn("gcore_seg_create failed!\n");
 739                 return (WALK_ERR);
 740         }
 741 
 742         /*
 743          * Iterate from the base of the segment to its end, allocating a new
 744          * prmap_node at each address boundary (baddr) between ranges that
 745          * have different virtual memory protections.
 746          */
 747         for (saddr = seg->s_base; saddr < eaddr; saddr = baddr) {
 748                 prot = gcore_pr_getprot(gs, &saddr, &baddr, eaddr);
 749                 if (saddr == eaddr) {
 750                         break;
 751                 }
 752 
 753                 mnode = mdb_alloc(sizeof (*mnode), UM_SLEEP);
 754                 mnode->next = NULL;
 755                 mp = &mnode->m;
 756 
 757                 if (cbarg->map_head == NULL) {
 758                         cbarg->map_head = cbarg->map_tail = mnode;
 759                 } else {
 760                         cbarg->map_tail->next = mnode;
 761                         cbarg->map_tail = mnode;
 762                 }
 763                 cbarg->map_len++;
 764 
 765                 mp->pr_vaddr = (uintptr_t)saddr;
 766                 mp->pr_size = baddr - saddr;
 767                 mp->pr_offset = GSOP_GETOFFSET(gs, saddr);
 768                 mp->pr_mflags = 0;
 769                 if (prot & PROT_READ)
 770                         mp->pr_mflags |= MA_READ;
 771                 if (prot & PROT_WRITE)
 772                         mp->pr_mflags |= MA_WRITE;
 773                 if (prot & PROT_EXEC)
 774                         mp->pr_mflags |= MA_EXEC;
 775                 if (GSOP_GETTYPE(gs, saddr) & MAP_SHARED)
 776                         mp->pr_mflags |= MA_SHARED;
 777                 if (GSOP_GETTYPE(gs, saddr) & MAP_NORESERVE)
 778                         mp->pr_mflags |= MA_NORESERVE;
 779                 if (seg->s_ops == gcore_segvn_ops) {
 780                         if (mdb_ctf_vread(&svd, "segvn_data_t",
 781                             "mdb_segvn_data_t", seg->s_data, 0) == 0 &&
 782                             svd.vp == NULL) {
 783                                 mp->pr_mflags |= MA_ANON;
 784                         }
 785                 }
 786                 if (seg_addr == cbarg->brkseg)
 787                         mp->pr_mflags |= MA_BREAK;
 788                 else if (seg_addr == cbarg->stkseg)
 789                         mp->pr_mflags |= MA_STACK;
 790 
 791                 mp->pr_pagesize = PAGESIZE;
 792 
 793                 /*
 794                  * Manufacture a filename for the "object" dir.
 795                  */
 796                 GSOP_NAME(gs, mp->pr_mapname, sizeof (mp->pr_mapname));
 797         }
 798 
 799         gcore_seg_destroy(gs);
 800 
 801         return (0);
 802 }
 803 
 804 /*
 805  * Helper functions for retrieving process and lwp state.
 806  */
 807 static int
 808 pcommon_init(mdb_proc_t *p, pcommon_t *pc)
 809 {
 810         mdb_pid_t       pid;
 811         mdb_sess_t      sess;
 812         mdb_task_t      task;
 813         mdb_kproject_t  proj;
 814         mdb_zone_t      zone;
 815 
 816         pc->pc_nlwp = p->p_lwpcnt;
 817         pc->pc_nzomb = p->p_zombcnt;
 818 
 819         if (mdb_ctf_vread(&pid, "struct pid", "mdb_pid_t", p->p_pidp, 0) ==
 820             -1) {
 821                 return (-1);
 822         }
 823         pc->pc_pid = pid.pid_id;
 824         pc->pc_ppid = p->p_ppid;
 825 
 826         if (mdb_ctf_vread(&pid, "struct pid", "mdb_pid_t", p->p_pgidp, 0) ==
 827             -1) {
 828                 return (-1);
 829         }
 830         pc->pc_pgid = pid.pid_id;
 831 
 832         if (mdb_ctf_vread(&sess, "sess_t", "mdb_sess_t", p->p_sessp, 0) ==
 833             -1) {
 834                 return (-1);
 835         }
 836         if (mdb_ctf_vread(&pid, "struct pid", "mdb_pid_t", sess.s_sidp, 0) ==
 837             -1) {
 838                 return (-1);
 839         }
 840         pc->pc_sid = pid.pid_id;
 841 
 842         if (mdb_ctf_vread(&task, "task_t", "mdb_task_t", p->p_task, 0) == -1) {
 843                 return (-1);
 844         }
 845         pc->pc_taskid = task.tk_tkid;
 846 
 847         if (mdb_ctf_vread(&proj, "kproject_t", "mdb_kproject_t", task.tk_proj,
 848             0) == -1) {
 849                 return (-1);
 850         }
 851         pc->pc_projid = proj.kpj_id;
 852 
 853         if (mdb_ctf_vread(&zone, "zone_t", "mdb_zone_t", p->p_zone, 0) == -1) {
 854                 return (-1);
 855         }
 856         pc->pc_zoneid = zone.zone_id;
 857 
 858         switch (p->p_model) {
 859         case DATAMODEL_ILP32:
 860                 pc->pc_dmodel = PR_MODEL_ILP32;
 861                 break;
 862         case DATAMODEL_LP64:
 863                 pc->pc_dmodel = PR_MODEL_LP64;
 864                 break;
 865         }
 866 
 867         return (0);
 868 }
 869 
 870 static uintptr_t
 871 gcore_prchoose(mdb_proc_t *p)
 872 {
 873         mdb_kthread_t   kthr;
 874         mdb_kthread_t   *t = &kthr;
 875         ushort_t        t_istop_whystop = 0;
 876         ushort_t        t_istop_whatstop = 0;
 877         uintptr_t       t_addr = NULL;
 878         uintptr_t       t_onproc = NULL; // running on processor
 879         uintptr_t       t_run = NULL;    // runnable, on disp queue
 880         uintptr_t       t_sleep = NULL;  // sleeping
 881         uintptr_t       t_susp = NULL;   // suspended stop
 882         uintptr_t       t_jstop = NULL;  // jobcontrol stop, w/o directed stop
 883         uintptr_t       t_jdstop = NULL; // jobcontrol stop with directed stop
 884         uintptr_t       t_req = NULL;    // requested stop
 885         uintptr_t       t_istop = NULL;  // event-of-interest stop
 886         uintptr_t       t_dtrace = NULL; // DTrace stop
 887 
 888         /*
 889          * If the agent lwp exists, it takes precedence over all others.
 890          */
 891         if ((t_addr = p->p_agenttp) != NULL) {
 892                 return (t_addr);
 893         }
 894 
 895         if ((t_addr = p->p_tlist) == NULL) /* start at the head of the list */
 896                 return (t_addr);
 897         do {            /* for each lwp in the process */
 898                 if (mdb_ctf_vread(&kthr, "kthread_t", "mdb_kthread_t",
 899                     t_addr, 0) == -1) {
 900                         return (0);
 901                 }
 902 
 903                 if (VSTOPPED(t)) {      /* virtually stopped */
 904                         if (t_req == NULL)
 905                                 t_req = t_addr;
 906                         continue;
 907                 }
 908 
 909                 switch (t->t_state) {
 910                 default:
 911                         return (0);
 912                 case TS_SLEEP:
 913                         if (t_sleep == NULL)
 914                                 t_sleep = t_addr;
 915                         break;
 916                 case TS_RUN:
 917                 case TS_WAIT:
 918                         if (t_run == NULL)
 919                                 t_run = t_addr;
 920                         break;
 921                 case TS_ONPROC:
 922                         if (t_onproc == NULL)
 923                                 t_onproc = t_addr;
 924                         break;
 925                         /*
 926                          * Threads in the zombie state have the lowest
 927                          * priority when selecting a representative lwp.
 928                          */
 929                 case TS_ZOMB:
 930                         break;
 931                 case TS_STOPPED:
 932                         switch (t->t_whystop) {
 933                         case PR_SUSPENDED:
 934                                 if (t_susp == NULL)
 935                                         t_susp = t_addr;
 936                                 break;
 937                         case PR_JOBCONTROL:
 938                                 if (t->t_proc_flag & TP_PRSTOP) {
 939                                         if (t_jdstop == NULL)
 940                                                 t_jdstop = t_addr;
 941                                 } else {
 942                                         if (t_jstop == NULL)
 943                                                 t_jstop = t_addr;
 944                                 }
 945                                 break;
 946                         case PR_REQUESTED:
 947                                 if (t->t_dtrace_stop && t_dtrace == NULL)
 948                                         t_dtrace = t_addr;
 949                                 else if (t_req == NULL)
 950                                         t_req = t_addr;
 951                                 break;
 952                         case PR_SYSENTRY:
 953                         case PR_SYSEXIT:
 954                         case PR_SIGNALLED:
 955                         case PR_FAULTED:
 956                                 /*
 957                                  * Make an lwp calling exit() be the
 958                                  * last lwp seen in the process.
 959                                  */
 960                                 if (t_istop == NULL ||
 961                                     (t_istop_whystop == PR_SYSENTRY &&
 962                                     t_istop_whatstop == SYS_exit)) {
 963                                         t_istop = t_addr;
 964                                         t_istop_whystop = t->t_whystop;
 965                                         t_istop_whatstop = t->t_whatstop;
 966                                 }
 967                                 break;
 968                         case PR_CHECKPOINT:     /* can't happen? */
 969                                 break;
 970                         default:
 971                                 return (0);
 972                         }
 973                         break;
 974                 }
 975         } while ((t_addr = t->t_forw) != p->p_tlist);
 976 
 977         if (t_onproc)
 978                 t_addr = t_onproc;
 979         else if (t_run)
 980                 t_addr = t_run;
 981         else if (t_sleep)
 982                 t_addr = t_sleep;
 983         else if (t_jstop)
 984                 t_addr = t_jstop;
 985         else if (t_jdstop)
 986                 t_addr = t_jdstop;
 987         else if (t_istop)
 988                 t_addr = t_istop;
 989         else if (t_dtrace)
 990                 t_addr = t_dtrace;
 991         else if (t_req)
 992                 t_addr = t_req;
 993         else if (t_susp)
 994                 t_addr = t_susp;
 995         else                    /* TS_ZOMB */
 996                 t_addr = p->p_tlist;
 997 
 998         return (t_addr);
 999 }
1000 
1001 /*
1002  * Fields not populated:
1003  *   - pr_stype
1004  *   - pr_oldpri
1005  *   - pr_nice
1006  *   - pr_time
1007  *   - pr_pctcpu
1008  *   - pr_cpu
1009  */
1010 static int
1011 gcore_prgetlwpsinfo(uintptr_t t_addr, mdb_kthread_t *t, lwpsinfo_t *psp)
1012 {
1013         char            c, state;
1014         mdb_cpu_t       cpu;
1015         mdb_lpl_t       lgrp;
1016         uintptr_t       str_addr;
1017 
1018         bzero(psp, sizeof (*psp));
1019 
1020         psp->pr_flag = 0;    /* lwpsinfo_t.pr_flag is deprecated */
1021         psp->pr_lwpid = t->t_tid;
1022         psp->pr_addr = t_addr;
1023         psp->pr_wchan = (uintptr_t)t->t_wchan;
1024 
1025         /* map the thread state enum into a process state enum */
1026         state = VSTOPPED(t) ? TS_STOPPED : t->t_state;
1027         switch (state) {
1028         case TS_SLEEP:          state = SSLEEP;         c = 'S';        break;
1029         case TS_RUN:            state = SRUN;           c = 'R';        break;
1030         case TS_ONPROC:         state = SONPROC;        c = 'O';        break;
1031         case TS_ZOMB:           state = SZOMB;          c = 'Z';        break;
1032         case TS_STOPPED:        state = SSTOP;          c = 'T';        break;
1033         case TS_WAIT:           state = SWAIT;          c = 'W';        break;
1034         default:                state = 0;              c = '?';        break;
1035         }
1036         psp->pr_state = state;
1037         psp->pr_sname = c;
1038         psp->pr_syscall = t->t_sysnum;
1039         psp->pr_pri = t->t_pri;
1040         psp->pr_start.tv_sec = t->t_start;
1041         psp->pr_start.tv_nsec = 0L;
1042 
1043         str_addr = (uintptr_t)gcore_sclass[t->t_cid].cl_name;
1044         if (mdb_readstr(psp->pr_clname, sizeof (psp->pr_clname) - 1, str_addr)
1045             == -1) {
1046                 mdb_warn("Failed to read string from %p\n", str_addr);
1047                 return (-1);
1048         }
1049         bzero(psp->pr_name, sizeof (psp->pr_name));
1050 
1051         if (mdb_ctf_vread(&cpu, "struct cpu", "mdb_cpu_t", t->t_cpu, 0) == -1) {
1052                 return (-1);
1053         }
1054         psp->pr_onpro = cpu.cpu_id;
1055         psp->pr_bindpro = t->t_bind_cpu;
1056         psp->pr_bindpset = t->t_bind_pset;
1057 
1058         if (mdb_ctf_vread(&lgrp, "lpl_t", "mdb_lpl_t", t->t_lpl, 0) == -1) {
1059                 return (-1);
1060         }
1061         psp->pr_lgrp = lgrp.lpl_lgrpid;
1062 
1063         return (0);
1064 }
1065 
1066 /*ARGSUSED*/
1067 static int
1068 gcore_lpsinfo_cb(mdb_proc_t *p, lwpent_t *lwent, void *data)
1069 {
1070         lwpsinfo_t      *lpsinfo = data;
1071         uintptr_t       t_addr = (uintptr_t)lwent->le_thread;
1072         mdb_kthread_t   kthrd;
1073 
1074         if (t_addr != 0) {
1075                 if (mdb_ctf_vread(&kthrd, "kthread_t", "mdb_kthread_t", t_addr,
1076                     0) == -1) {
1077                         return (-1);
1078                 }
1079                 return (gcore_prgetlwpsinfo(t_addr, &kthrd, lpsinfo));
1080         }
1081 
1082         bzero(lpsinfo, sizeof (*lpsinfo));
1083         lpsinfo->pr_lwpid = lwent->le_lwpid;
1084         lpsinfo->pr_state = SZOMB;
1085         lpsinfo->pr_sname = 'Z';
1086         lpsinfo->pr_start.tv_sec = lwent->le_start;
1087         lpsinfo->pr_bindpro = PBIND_NONE;
1088         lpsinfo->pr_bindpset = PS_NONE;
1089         return (0);
1090 }
1091 
1092 static void
1093 gcore_schedctl_finish_sigblock(mdb_kthread_t *t)
1094 {
1095         mdb_sc_shared_t td;
1096         mdb_sc_shared_t *tdp;
1097 
1098         if (t->t_schedctl == NULL) {
1099                 return;
1100         }
1101 
1102         if (mdb_ctf_vread(&td, "sc_shared_t", "mdb_sc_shared_t", t->t_schedctl,
1103             0) == -1) {
1104                 return;
1105         }
1106         tdp = &td;
1107 
1108         if (tdp->sc_sigblock) {
1109                 t->t_hold.__sigbits[0] = FILLSET0 & ~CANTMASK0;
1110                 t->t_hold.__sigbits[1] = FILLSET1 & ~CANTMASK1;
1111                 t->t_hold.__sigbits[2] = FILLSET2 & ~CANTMASK2;
1112                 tdp->sc_sigblock = 0;
1113         }
1114 }
1115 
1116 static void
1117 gcore_prgetaction(mdb_proc_t *p, user_t *up, uint_t sig, struct sigaction *sp)
1118 {
1119         int nsig = NSIG;
1120 
1121         bzero(sp, sizeof (*sp));
1122 
1123         if (sig != 0 && (unsigned)sig < nsig) {
1124                 sp->sa_handler = up->u_signal[sig-1];
1125                 prassignset(&sp->sa_mask, &up->u_sigmask[sig-1]);
1126                 if (sigismember(&up->u_sigonstack, sig))
1127                         sp->sa_flags |= SA_ONSTACK;
1128                 if (sigismember(&up->u_sigresethand, sig))
1129                         sp->sa_flags |= SA_RESETHAND;
1130                 if (sigismember(&up->u_sigrestart, sig))
1131                         sp->sa_flags |= SA_RESTART;
1132                 if (sigismember(&p->p_siginfo, sig))
1133                         sp->sa_flags |= SA_SIGINFO;
1134                 if (sigismember(&up->u_signodefer, sig))
1135                         sp->sa_flags |= SA_NODEFER;
1136                 if (sig == SIGCLD) {
1137                         if (p->p_flag & SNOWAIT)
1138                                 sp->sa_flags |= SA_NOCLDWAIT;
1139                         if ((p->p_flag & SJCTL) == 0)
1140                                 sp->sa_flags |= SA_NOCLDSTOP;
1141                 }
1142         }
1143 }
1144 
1145 static void
1146 gcore_prgetprregs(mdb_klwp_t *lwp, prgregset_t prp)
1147 {
1148         gcore_getgregs(lwp, prp);
1149 }
1150 
1151 /*
1152  * Field not populated:
1153  *   - pr_tstamp
1154  *   - pr_utime
1155  *   - pr_stime
1156  *   - pr_syscall
1157  *   - pr_syarg
1158  *   - pr_nsysarg
1159  *   - pr_fpreg
1160  */
1161 /*ARGSUSED*/
1162 static int
1163 gcore_prgetlwpstatus(mdb_proc_t *p, uintptr_t t_addr, mdb_kthread_t *t,
1164     lwpstatus_t *sp, zone_t *zp)
1165 {
1166         uintptr_t       lwp_addr = ttolwp(t);
1167         mdb_klwp_t      lw;
1168         mdb_klwp_t      *lwp;
1169         ulong_t         instr;
1170         int             flags;
1171         uintptr_t       str_addr;
1172         struct pid      pid;
1173 
1174         if (mdb_ctf_vread(&lw, "klwp_t", "mdb_klwp_t", lwp_addr, 0) == -1) {
1175                 return (-1);
1176         }
1177         lwp = &lw;
1178 
1179         bzero(sp, sizeof (*sp));
1180         flags = 0L;
1181         if (t->t_state == TS_STOPPED) {
1182                 flags |= PR_STOPPED;
1183                 if ((t->t_schedflag & TS_PSTART) == 0)
1184                         flags |= PR_ISTOP;
1185         } else if (VSTOPPED(t)) {
1186                 flags |= PR_STOPPED|PR_ISTOP;
1187         }
1188         if (!(flags & PR_ISTOP) && (t->t_proc_flag & TP_PRSTOP))
1189                 flags |= PR_DSTOP;
1190         if (lwp->lwp_asleep)
1191                 flags |= PR_ASLEEP;
1192         if (t_addr == p->p_agenttp)
1193                 flags |= PR_AGENT;
1194         if (!(t->t_proc_flag & TP_TWAIT))
1195                 flags |= PR_DETACH;
1196         if (t->t_proc_flag & TP_DAEMON)
1197                 flags |= PR_DAEMON;
1198         if (p->p_proc_flag & P_PR_FORK)
1199                 flags |= PR_FORK;
1200         if (p->p_proc_flag & P_PR_RUNLCL)
1201                 flags |= PR_RLC;
1202         if (p->p_proc_flag & P_PR_KILLCL)
1203                 flags |= PR_KLC;
1204         if (p->p_proc_flag & P_PR_ASYNC)
1205                 flags |= PR_ASYNC;
1206         if (p->p_proc_flag & P_PR_BPTADJ)
1207                 flags |= PR_BPTADJ;
1208         if (p->p_proc_flag & P_PR_PTRACE)
1209                 flags |= PR_PTRACE;
1210         if (p->p_flag & SMSACCT)
1211                 flags |= PR_MSACCT;
1212         if (p->p_flag & SMSFORK)
1213                 flags |= PR_MSFORK;
1214         if (p->p_flag & SVFWAIT)
1215                 flags |= PR_VFORKP;
1216 
1217         if (mdb_vread(&pid, sizeof (struct pid), p->p_pgidp) != sizeof (pid)) {
1218                 mdb_warn("Failed to read pid from %p\n", p->p_pgidp);
1219                 return (-1);
1220         }
1221         if (pid.pid_pgorphaned)
1222                 flags |= PR_ORPHAN;
1223         if (p->p_pidflag & CLDNOSIGCHLD)
1224                 flags |= PR_NOSIGCHLD;
1225         if (p->p_pidflag & CLDWAITPID)
1226                 flags |= PR_WAITPID;
1227         sp->pr_flags = flags;
1228         if (VSTOPPED(t)) {
1229                 sp->pr_why   = PR_REQUESTED;
1230                 sp->pr_what  = 0;
1231         } else {
1232                 sp->pr_why   = t->t_whystop;
1233                 sp->pr_what  = t->t_whatstop;
1234         }
1235         sp->pr_lwpid = t->t_tid;
1236         sp->pr_cursig  = lwp->lwp_cursig;
1237         prassignset(&sp->pr_lwppend, &t->t_sig);
1238         gcore_schedctl_finish_sigblock(t);
1239         prassignset(&sp->pr_lwphold, &t->t_hold);
1240         if (t->t_whystop == PR_FAULTED) {
1241                 bcopy(&lwp->lwp_siginfo,
1242                     &sp->pr_info, sizeof (k_siginfo_t));
1243         } else if (lwp->lwp_curinfo) {
1244                 mdb_sigqueue_t  sigq;
1245 
1246                 if (mdb_ctf_vread(&sigq, "sigqueue_t", "mdb_sigqueue_t",
1247                     lwp->lwp_curinfo, 0) == -1) {
1248                         return (-1);
1249                 }
1250                 bcopy(&sigq.sq_info, &sp->pr_info, sizeof (k_siginfo_t));
1251         }
1252 
1253         sp->pr_altstack = lwp->lwp_sigaltstack;
1254         gcore_prgetaction(p, PTOU(p), lwp->lwp_cursig, &sp->pr_action);
1255         sp->pr_oldcontext = lwp->lwp_oldcontext;
1256         sp->pr_ustack = lwp->lwp_ustack;
1257 
1258         str_addr = (uintptr_t)gcore_sclass[t->t_cid].cl_name;
1259         if (mdb_readstr(sp->pr_clname, sizeof (sp->pr_clname) - 1, str_addr) ==
1260             -1) {
1261                 mdb_warn("Failed to read string from %p\n", str_addr);
1262                 return (-1);
1263         }
1264 
1265         /*
1266          * Fetch the current instruction, if not a system process.
1267          * We don't attempt this unless the lwp is stopped.
1268          */
1269         if ((p->p_flag & SSYS) || p->p_as == gcore_kas)
1270                 sp->pr_flags |= (PR_ISSYS|PR_PCINVAL);
1271         else if (!(flags & PR_STOPPED))
1272                 sp->pr_flags |= PR_PCINVAL;
1273         else if (!gcore_prfetchinstr(lwp, &instr))
1274                 sp->pr_flags |= PR_PCINVAL;
1275         else
1276                 sp->pr_instr = instr;
1277 
1278         if (gcore_prisstep(lwp))
1279                 sp->pr_flags |= PR_STEP;
1280         gcore_prgetprregs(lwp, sp->pr_reg);
1281         if ((t->t_state == TS_STOPPED && t->t_whystop == PR_SYSEXIT) ||
1282             (flags & PR_VFORKP)) {
1283                 user_t *up;
1284                 auxv_t *auxp;
1285                 int i;
1286 
1287                 sp->pr_errno = gcore_prgetrvals(lwp, &sp->pr_rval1,
1288                     &sp->pr_rval2);
1289                 if (sp->pr_errno == 0)
1290                         sp->pr_errpriv = PRIV_NONE;
1291                 else
1292                         sp->pr_errpriv = lwp->lwp_badpriv;
1293 
1294                 if (t->t_sysnum == SYS_execve) {
1295                         up = PTOU(p);
1296                         sp->pr_sysarg[0] = 0;
1297                         sp->pr_sysarg[1] = (uintptr_t)up->u_argv;
1298                         sp->pr_sysarg[2] = (uintptr_t)up->u_envp;
1299                         for (i = 0, auxp = up->u_auxv;
1300                             i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
1301                             i++, auxp++) {
1302                                 if (auxp->a_type == AT_SUN_EXECNAME) {
1303                                         sp->pr_sysarg[0] =
1304                                             (uintptr_t)auxp->a_un.a_ptr;
1305                                         break;
1306                                 }
1307                         }
1308                 }
1309         }
1310         return (0);
1311 }
1312 
1313 static int
1314 gcore_lstatus_cb(mdb_proc_t *p, lwpent_t *lwent, void *data)
1315 {
1316         lwpstatus_t     *lstatus = data;
1317         uintptr_t       t_addr = (uintptr_t)lwent->le_thread;
1318         mdb_kthread_t   kthrd;
1319 
1320         if (t_addr == NULL) {
1321                 return (1);
1322         }
1323 
1324         if (mdb_ctf_vread(&kthrd, "kthread_t", "mdb_kthread_t", t_addr, 0)
1325             == -1) {
1326                 return (-1);
1327         }
1328 
1329         return (gcore_prgetlwpstatus(p, t_addr, &kthrd, lstatus, NULL));
1330 }
1331 
1332 static prheader_t *
1333 gcore_walk_lwps(mdb_proc_t *p, lwp_callback_t callback, int nlwp,
1334     size_t ent_size)
1335 {
1336         void            *ent;
1337         prheader_t      *php;
1338         lwpdir_t        *ldp;
1339         lwpdir_t        ld;
1340         lwpent_t        lwent;
1341         int             status;
1342         int             i;
1343 
1344         php = calloc(1, sizeof (prheader_t) + nlwp * ent_size);
1345         if (php == NULL) {
1346                 return (NULL);
1347         }
1348         php->pr_nent = nlwp;
1349         php->pr_entsize = ent_size;
1350 
1351         ent = php + 1;
1352         for (ldp = (lwpdir_t *)p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++,
1353             ldp++) {
1354                 if (mdb_vread(&ld, sizeof (ld), (uintptr_t)ldp) !=
1355                     sizeof (ld)) {
1356                         mdb_warn("Failed to read lwpdir_t from %p\n", ldp);
1357                         goto error;
1358                 }
1359 
1360                 if (ld.ld_entry == NULL) {
1361                         continue;
1362                 }
1363 
1364                 if (mdb_vread(&lwent, sizeof (lwent), (uintptr_t)ld.ld_entry) !=
1365                     sizeof (lwent)) {
1366                         mdb_warn("Failed to read lwpent_t from %p\n",
1367                             ld.ld_entry);
1368                         goto error;
1369                 }
1370 
1371                 status = callback(p, &lwent, ent);
1372                 if (status == -1) {
1373                         dprintf("lwp callback %p returned -1\n", callback);
1374                         goto error;
1375                 }
1376                 if (status == 1) {
1377                         dprintf("lwp callback %p returned 1\n", callback);
1378                         continue;
1379                 }
1380 
1381                 ent = (caddr_t)ent + ent_size;
1382         }
1383 
1384         return (php);
1385 
1386 error:
1387         free(php);
1388         return (NULL);
1389 }
1390 
1391 /*
1392  * Misc helper functions.
1393  */
1394 /*
1395  * convert code/data pair into old style wait status
1396  */
1397 static int
1398 gcore_wstat(int code, int data)
1399 {
1400         int stat = (data & 0377);
1401 
1402         switch (code) {
1403         case CLD_EXITED:
1404                 stat <<= 8;
1405                 break;
1406         case CLD_DUMPED:
1407                 stat |= WCOREFLG;
1408                 break;
1409         case CLD_KILLED:
1410                 break;
1411         case CLD_TRAPPED:
1412         case CLD_STOPPED:
1413                 stat <<= 8;
1414                 stat |= WSTOPFLG;
1415                 break;
1416         case CLD_CONTINUED:
1417                 stat = WCONTFLG;
1418                 break;
1419         default:
1420                 mdb_warn("wstat: bad code %d\n", code);
1421         }
1422         return (stat);
1423 }
1424 
1425 #if defined(__i386) || defined(__amd64)
1426 static void
1427 gcore_usd_to_ssd(user_desc_t *usd, struct ssd *ssd, selector_t sel)
1428 {
1429         ssd->bo = USEGD_GETBASE(usd);
1430         ssd->ls = USEGD_GETLIMIT(usd);
1431         ssd->sel = sel;
1432 
1433         /*
1434          * set type, dpl and present bits.
1435          */
1436         ssd->acc1 = usd->usd_type;
1437         ssd->acc1 |= usd->usd_dpl << 5;
1438         ssd->acc1 |= usd->usd_p << (5 + 2);
1439 
1440         /*
1441          * set avl, DB and granularity bits.
1442          */
1443         ssd->acc2 = usd->usd_avl;
1444 
1445 #if defined(__amd64)
1446         ssd->acc2 |= usd->usd_long << 1;
1447 #else
1448         ssd->acc2 |= usd->usd_reserved << 1;
1449 #endif
1450 
1451         ssd->acc2 |= usd->usd_def32 << (1 + 1);
1452         ssd->acc2 |= usd->usd_gran << (1 + 1 + 1);
1453 }
1454 #endif
1455 
1456 static priv_set_t *
1457 gcore_priv_getset(cred_t *cr, int set)
1458 {
1459         if ((CR_FLAGS(cr) & PRIV_AWARE) == 0) {
1460                 switch (set) {
1461                 case PRIV_EFFECTIVE:
1462                         return (&CR_OEPRIV(cr));
1463                 case PRIV_PERMITTED:
1464                         return (&CR_OPPRIV(cr));
1465                 }
1466         }
1467         return (&CR_PRIVS(cr)->crprivs[set]);
1468 }
1469 
1470 static void
1471 gcore_priv_getinfo(const cred_t *cr, void *buf)
1472 {
1473         struct priv_info_uint *ii;
1474 
1475         ii = buf;
1476         ii->val = CR_FLAGS(cr);
1477         ii->info.priv_info_size = (uint32_t)sizeof (*ii);
1478         ii->info.priv_info_type = PRIV_INFO_FLAGS;
1479 }
1480 
1481 static void
1482 map_list_free(prmap_node_t *n)
1483 {
1484         prmap_node_t    *next;
1485 
1486         while (n != NULL) {
1487                 next = n->next;
1488                 mdb_free(n, sizeof (*n));
1489                 n = next;
1490         }
1491 }
1492 
1493 /*
1494  * Ops vector functions for ::gcore.
1495  */
1496 /*ARGSUSED*/
1497 static ssize_t
1498 Pread_gcore(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr,
1499     void *data)
1500 {
1501         mdb_proc_t      *p = data;
1502         ssize_t         ret;
1503 
1504         ret = mdb_aread(buf, n, addr, (void *)p->p_as);
1505         if (ret != n) {
1506                 dprintf("%s: addr: %p len: %llx\n", __func__, addr, n);
1507                 (void) memset(buf, 0, n);
1508                 return (n);
1509         }
1510 
1511         return (ret);
1512 }
1513 
1514 /*ARGSUSED*/
1515 static ssize_t
1516 Pwrite_gcore(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr,
1517     void *data)
1518 {
1519         dprintf("%s: addr: %p len: %llx\n", __func__, addr, n);
1520 
1521         return (-1);
1522 }
1523 
1524 /*ARGSUSED*/
1525 static int
1526 Pread_maps_gcore(struct ps_prochandle *P, prmap_t **Pmapp, ssize_t *nmapp,
1527     void *data)
1528 {
1529         mdb_proc_t      *p = data;
1530         read_maps_cbarg_t cbarg;
1531         prmap_node_t    *n;
1532         prmap_t         *pmap;
1533         uintptr_t       segtree_addr;
1534         int             error;
1535         int             i;
1536 
1537         cbarg.p = p;
1538         cbarg.brkseg = gcore_break_seg(p);
1539         cbarg.stkseg = gcore_as_segat(p->p_as, gcore_prgetstackbase(p));
1540 
1541         (void) memset(&cbarg, 0, sizeof (cbarg));
1542         segtree_addr = p->p_as + mdb_ctf_offsetof_by_name("struct as",
1543             "a_segtree");
1544         error = avl_walk_mdb(segtree_addr, read_maps_cb, &cbarg);
1545         if (error != WALK_DONE) {
1546                 return (-1);
1547         }
1548 
1549         /* Conver the linked list into an array */
1550         pmap = malloc(cbarg.map_len * sizeof (*pmap));
1551         if (pmap == NULL) {
1552                 map_list_free(cbarg.map_head);
1553                 return (-1);
1554         }
1555 
1556         for (i = 0, n = cbarg.map_head; i < cbarg.map_len; i++, n = n->next) {
1557                 (void) memcpy(&pmap[i], &n->m, sizeof (prmap_t));
1558         }
1559         map_list_free(cbarg.map_head);
1560 
1561         for (i = 0; i < cbarg.map_len; i++) {
1562                 dprintf("pr_vaddr: %p pr_size: %llx, pr_name: %s "
1563                     "pr_offset: %p pr_mflags: 0x%x\n",
1564                     pmap[i].pr_vaddr, pmap[i].pr_size,
1565                     pmap[i].pr_mapname, pmap[i].pr_offset,
1566                     pmap[i].pr_mflags);
1567         }
1568 
1569         *Pmapp = pmap;
1570         *nmapp = cbarg.map_len;
1571 
1572         return (0);
1573 }
1574 
1575 /*ARGSUSED*/
1576 static void
1577 Pread_aux_gcore(struct ps_prochandle *P, auxv_t **auxvp, int *nauxp, void *data)
1578 {
1579         mdb_proc_t      *p = data;
1580         auxv_t          *auxv;
1581         int             naux;
1582 
1583         naux = __KERN_NAUXV_IMPL;
1584         auxv = calloc(naux + 1, sizeof (*auxv));
1585         if (auxv == NULL) {
1586                 *auxvp = NULL;
1587                 *nauxp = 0;
1588                 return;
1589         }
1590 
1591         (void) memcpy(auxv, p->p_user.u_auxv, naux * sizeof (*auxv));
1592 
1593         *auxvp = auxv;
1594         *nauxp = naux;
1595 }
1596 
1597 /*ARGSUSED*/
1598 static int
1599 Pcred_gcore(struct ps_prochandle *P, prcred_t *prcp, int ngroups, void *data)
1600 {
1601         mdb_proc_t      *p = data;
1602         cred_t          cr;
1603         credgrp_t       crgrp;
1604         int             i;
1605 
1606         if (mdb_vread(&cr, sizeof (cr), p->p_cred) != sizeof (cr)) {
1607                 mdb_warn("Failed to read cred_t from %p\n", p->p_cred);
1608                 return (-1);
1609         }
1610 
1611         prcp->pr_euid = cr.cr_uid;
1612         prcp->pr_ruid = cr.cr_ruid;
1613         prcp->pr_suid = cr.cr_suid;
1614         prcp->pr_egid = cr.cr_gid;
1615         prcp->pr_rgid = cr.cr_rgid;
1616         prcp->pr_sgid = cr.cr_sgid;
1617 
1618         if (cr.cr_grps == 0) {
1619                 prcp->pr_ngroups = 0;
1620                 return (0);
1621         }
1622 
1623         if (mdb_vread(&crgrp, sizeof (crgrp), (uintptr_t)cr.cr_grps) !=
1624             sizeof (crgrp)) {
1625                 mdb_warn("Failed to read credgrp_t from %p\n", cr.cr_grps);
1626                 return (-1);
1627         }
1628 
1629         prcp->pr_ngroups = MIN(ngroups, crgrp.crg_ngroups);
1630         for (i = 0; i < prcp->pr_ngroups; i++) {
1631                 prcp->pr_groups[i] = crgrp.crg_groups[i];
1632         }
1633 
1634         return (0);
1635 }
1636 
1637 /*ARGSUSED*/
1638 static int
1639 Ppriv_gcore(struct ps_prochandle *P, prpriv_t **pprv, void *data)
1640 {
1641         mdb_proc_t      *p = data;
1642         prpriv_t        *pp;
1643         cred_t          cr;
1644         priv_set_t      *psa;
1645         size_t          pprv_size;
1646         int             i;
1647 
1648         pprv_size = sizeof (prpriv_t) + PRIV_SETBYTES - sizeof (priv_chunk_t) +
1649             prinfo.priv_infosize;
1650 
1651         pp = malloc(pprv_size);
1652         if (pp == NULL) {
1653                 return (-1);
1654         }
1655 
1656         if (mdb_vread(&cr, sizeof (cr), p->p_cred) != sizeof (cr)) {
1657                 mdb_warn("Failed to read cred_t from %p\n", p->p_cred);
1658                 free(pp);
1659                 return (-1);
1660         }
1661 
1662         pp->pr_nsets = PRIV_NSET;
1663         pp->pr_setsize = PRIV_SETSIZE;
1664         pp->pr_infosize = prinfo.priv_infosize;
1665 
1666         psa = (priv_set_t *)pp->pr_sets;
1667         for (i = 0; i < PRIV_NSET; i++) {
1668                 psa[i] = *gcore_priv_getset(&cr, i);
1669         }
1670 
1671         gcore_priv_getinfo(&cr, (char *)pp + PRIV_PRPRIV_INFO_OFFSET(pp));
1672 
1673         *pprv = pp;
1674         return (0);
1675 }
1676 
1677 /*
1678  * Fields not filled populated:
1679  *   - pr_utime
1680  *   - pr_stkbase
1681  *   - pr_cutime
1682  *   - pr_cstime
1683  *   - pr_agentid
1684  */
1685 /*ARGSUSED*/
1686 static void
1687 Pstatus_gcore(struct ps_prochandle *P, pstatus_t *sp, void *data)
1688 {
1689         mdb_proc_t      *p = data;
1690         uintptr_t       t_addr;
1691         mdb_kthread_t   kthr;
1692         mdb_kthread_t   *t;
1693         pcommon_t       pc;
1694 
1695         t_addr = gcore_prchoose(p);
1696         if (t_addr != NULL) {
1697                 if (mdb_ctf_vread(&kthr, "kthread_t", "mdb_kthread_t", t_addr,
1698                     0) == -1) {
1699                         return;
1700                 }
1701                 t = &kthr;
1702         }
1703 
1704         /* just bzero the process part, prgetlwpstatus() does the rest */
1705         bzero(sp, sizeof (pstatus_t) - sizeof (lwpstatus_t));
1706 
1707         if (pcommon_init(p, &pc) == -1) {
1708                 return;
1709         }
1710         sp->pr_nlwp = pc.pc_nlwp;
1711         sp->pr_nzomb = pc.pc_nzomb;
1712         sp->pr_pid = pc.pc_pid;
1713         sp->pr_ppid = pc.pc_ppid;
1714         sp->pr_pgid = pc.pc_pgid;
1715         sp->pr_sid = pc.pc_sid;
1716         sp->pr_taskid = pc.pc_taskid;
1717         sp->pr_projid = pc.pc_projid;
1718         sp->pr_zoneid = pc.pc_zoneid;
1719         sp->pr_dmodel = pc.pc_dmodel;
1720 
1721         prassignset(&sp->pr_sigpend, &p->p_sig);
1722         sp->pr_brkbase = p->p_brkbase;
1723         sp->pr_brksize = p->p_brksize;
1724         sp->pr_stkbase = gcore_prgetstackbase(p);
1725         sp->pr_stksize = p->p_stksize;
1726 
1727         prassignset(&sp->pr_sigtrace, &p->p_sigmask);
1728         prassignset(&sp->pr_flttrace, &p->p_fltmask);
1729         prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
1730         prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
1731 
1732         /* get the chosen lwp's status */
1733         gcore_prgetlwpstatus(p, t_addr, t, &sp->pr_lwp, NULL);
1734 
1735         /* replicate the flags */
1736         sp->pr_flags = sp->pr_lwp.pr_flags;
1737 }
1738 
1739 /*
1740  * Fields not populated:
1741  *   - pr_contract
1742  *   - pr_addr
1743  *   - pr_rtime
1744  *   - pr_ctime
1745  *   - pr_ttydev
1746  *   - pr_pctcpu
1747  *   - pr_size
1748  *   - pr_rsize
1749  *   - pr_pctmem
1750  */
1751 /*ARGSUSED*/
1752 static const psinfo_t *
1753 Ppsinfo_gcore(struct ps_prochandle *P, psinfo_t *psp, void *data)
1754 {
1755         mdb_proc_t      *p = data;
1756         mdb_kthread_t   *t;
1757         mdb_pool_t      pool;
1758         cred_t          cr;
1759         uintptr_t       t_addr;
1760         pcommon_t       pc;
1761 
1762         if ((t_addr = gcore_prchoose(p)) == NULL) {
1763                 bzero(psp, sizeof (*psp));
1764         } else {
1765                 bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
1766         }
1767 
1768         if (pcommon_init(p, &pc) == -1) {
1769                 return (NULL);
1770         }
1771         psp->pr_nlwp = pc.pc_nlwp;
1772         psp->pr_nzomb = pc.pc_nzomb;
1773         psp->pr_pid = pc.pc_pid;
1774         psp->pr_ppid = pc.pc_ppid;
1775         psp->pr_pgid = pc.pc_pgid;
1776         psp->pr_sid = pc.pc_sid;
1777         psp->pr_taskid = pc.pc_taskid;
1778         psp->pr_projid = pc.pc_projid;
1779         psp->pr_dmodel = pc.pc_dmodel;
1780 
1781         /*
1782          * only export SSYS and SMSACCT; everything else is off-limits to
1783          * userland apps.
1784          */
1785         psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
1786 
1787         if (mdb_vread(&cr, sizeof (cr), p->p_cred) != sizeof (cr)) {
1788                 mdb_warn("Failed to read cred_t from %p\n", p->p_cred);
1789                 return (NULL);
1790         }
1791 
1792         psp->pr_uid = cr.cr_ruid;
1793         psp->pr_euid = cr.cr_uid;
1794         psp->pr_gid = cr.cr_rgid;
1795         psp->pr_egid = cr.cr_gid;
1796 
1797         if (mdb_ctf_vread(&pool, "pool_t", "mdb_pool_t", p->p_pool, 0) == -1) {
1798                 return (NULL);
1799         }
1800         psp->pr_poolid = pool.pool_id;
1801 
1802         if (t_addr == 0) {
1803                 int wcode = p->p_wcode;
1804 
1805                 if (wcode)
1806                         psp->pr_wstat = gcore_wstat(wcode, p->p_wdata);
1807                 psp->pr_ttydev = PRNODEV;
1808                 psp->pr_lwp.pr_state = SZOMB;
1809                 psp->pr_lwp.pr_sname = 'Z';
1810                 psp->pr_lwp.pr_bindpro = PBIND_NONE;
1811                 psp->pr_lwp.pr_bindpset = PS_NONE;
1812         } else {
1813                 mdb_kthread_t   kthr;
1814                 user_t          *up = PTOU(p);
1815 
1816                 psp->pr_start = up->u_start;
1817                 bcopy(up->u_comm, psp->pr_fname,
1818                     MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
1819                 bcopy(up->u_psargs, psp->pr_psargs,
1820                     MIN(PRARGSZ-1, PSARGSZ));
1821 
1822                 psp->pr_argc = up->u_argc;
1823                 psp->pr_argv = up->u_argv;
1824                 psp->pr_envp = up->u_envp;
1825 
1826                 /* get the chosen lwp's lwpsinfo */
1827                 if (mdb_ctf_vread(&kthr, "kthread_t", "mdb_kthread_t", t_addr,
1828                     0) == -1) {
1829                         return (NULL);
1830                 }
1831                 t = &kthr;
1832 
1833                 gcore_prgetlwpsinfo(t_addr, t, &psp->pr_lwp);
1834         }
1835 
1836         return (NULL);
1837 }
1838 
1839 /*ARGSUSED*/
1840 static prheader_t *
1841 Plstatus_gcore(struct ps_prochandle *P, void *data)
1842 {
1843         mdb_proc_t      *p = data;
1844         int             nlwp = p->p_lwpcnt;
1845         size_t          ent_size = LSPAN(lwpstatus_t);
1846 
1847         return (gcore_walk_lwps(p, gcore_lstatus_cb, nlwp, ent_size));
1848 }
1849 
1850 /*ARGSUSED*/
1851 static prheader_t *
1852 Plpsinfo_gcore(struct ps_prochandle *P, void *data)
1853 {
1854         mdb_proc_t      *p = data;
1855         int             nlwp = p->p_lwpcnt + p->p_zombcnt;
1856         size_t          ent_size = LSPAN(lwpsinfo_t);
1857 
1858         return (gcore_walk_lwps(p, gcore_lpsinfo_cb, nlwp, ent_size));
1859 }
1860 
1861 /*ARGSUSED*/
1862 static char *
1863 Pplatform_gcore(struct ps_prochandle *P, char *s, size_t n, void *data)
1864 {
1865         char    platform[SYS_NMLN];
1866 
1867         if (mdb_readvar(platform, "platform") == -1) {
1868                 mdb_warn("failed to read platform!\n");
1869                 return (NULL);
1870         }
1871         dprintf("platform: %s\n", platform);
1872 
1873         (void) strncpy(s, platform, n);
1874         return (s);
1875 }
1876 
1877 /*ARGSUSED*/
1878 static int
1879 Puname_gcore(struct ps_prochandle *P, struct utsname *u, void *data)
1880 {
1881         if (mdb_readvar(u, "utsname") != sizeof (*u)) {
1882                 return (-1);
1883         }
1884 
1885         return (0);
1886 }
1887 
1888 /*ARGSUSED*/
1889 static char *
1890 Pzonename_gcore(struct ps_prochandle *P, char *s, size_t n, void *data)
1891 {
1892         mdb_proc_t      *p = data;
1893         mdb_zone_t      zone;
1894 
1895         if (mdb_ctf_vread(&zone, "zone_t", "mdb_zone_t", p->p_zone, 0) == -1) {
1896                 return (NULL);
1897         }
1898 
1899         if (mdb_readstr(s, n, zone.zone_name) == -1) {
1900                 mdb_warn("Failed to read zone name from %p\n", zone.zone_name);
1901                 return (NULL);
1902         }
1903 
1904         return (s);
1905 }
1906 
1907 /*ARGSUSED*/
1908 static char *
1909 Pexecname_gcore(struct ps_prochandle *P, char *buf, size_t buflen, void *data)
1910 {
1911         mdb_proc_t      *p = data;
1912         mdb_vnode_t     vn;
1913 
1914         if (mdb_ctf_vread(&vn, "vnode_t", "mdb_vnode_t", p->p_exec, 0) == -1) {
1915                 return (NULL);
1916         }
1917 
1918         if (mdb_readstr(buf, buflen, vn.v_path) == -1) {
1919                 mdb_warn("Failed to read vnode path from %p\n", vn.v_path);
1920                 return (NULL);
1921         }
1922 
1923         dprintf("execname: %s\n", buf);
1924 
1925         return (buf);
1926 }
1927 
1928 #if defined(__i386) || defined(__amd64)
1929 /*ARGSUSED*/
1930 static int
1931 Pldt_gcore(struct ps_prochandle *P, struct ssd *pldt, int nldt, void *data)
1932 {
1933         mdb_proc_t      *p = data;
1934         user_desc_t     *udp;
1935         user_desc_t     *ldts;
1936         size_t          ldt_size;
1937         int             i, limit;
1938 
1939         if (p->p_ldt == NULL) {
1940                 return (0);
1941         }
1942 
1943         limit = p->p_ldtlimit;
1944 
1945         /* Is this call just to query the size ? */
1946         if (pldt == NULL || nldt == 0) {
1947                 return (limit);
1948         }
1949 
1950         ldt_size = limit * sizeof (*ldts);
1951         ldts = malloc(ldt_size);
1952         if (ldts == NULL) {
1953                 mdb_warn("Failed to malloc ldts (size %lld)n", ldt_size);
1954                 return (-1);
1955         }
1956 
1957         if (mdb_vread(ldts, ldt_size, p->p_ldt) != ldt_size) {
1958                 mdb_warn("Failed to read ldts from %p\n", p->p_ldt);
1959                 free(ldts);
1960                 return (-1);
1961         }
1962 
1963         for (i = LDT_UDBASE, udp = &ldts[i]; i <= limit; i++, udp++) {
1964                 if (udp->usd_type != 0 || udp->usd_dpl != 0 ||
1965                     udp->usd_p != 0) {
1966                         gcore_usd_to_ssd(udp, pldt++, SEL_LDT(i));
1967                 }
1968         }
1969 
1970         free(ldts);
1971         return (limit);
1972 }
1973 #endif
1974 
1975 static const ps_ops_t Pgcore_ops = {
1976         .pop_pread      = Pread_gcore,
1977         .pop_pwrite     = Pwrite_gcore,
1978         .pop_read_maps  = Pread_maps_gcore,
1979         .pop_read_aux   = Pread_aux_gcore,
1980         .pop_cred       = Pcred_gcore,
1981         .pop_priv       = Ppriv_gcore,
1982         .pop_psinfo     = Ppsinfo_gcore,
1983         .pop_status     = Pstatus_gcore,
1984         .pop_lstatus    = Plstatus_gcore,
1985         .pop_lpsinfo    = Plpsinfo_gcore,
1986         .pop_platform   = Pplatform_gcore,
1987         .pop_uname      = Puname_gcore,
1988         .pop_zonename   = Pzonename_gcore,
1989         .pop_execname   = Pexecname_gcore,
1990 #if defined(__i386) || defined(__amd64)
1991         .pop_ldt        = Pldt_gcore
1992 #endif
1993 };
1994 
1995 /*ARGSUSED*/
1996 int
1997 gcore_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1998 {
1999         struct ps_prochandle *P;
2000         char            core_name[MAXNAMELEN];
2001         mdb_proc_t      p;
2002         mdb_pid_t       pid;
2003         int             error;
2004 
2005         if (!gcore_initialized) {
2006                 mdb_warn("gcore unavailable\n");
2007                 return (DCMD_ERR);
2008         }
2009 
2010         if (mdb_ctf_vread(&p, "proc_t", "mdb_proc_t", addr, 0) == -1) {
2011                 return (DCMD_ERR);
2012         }
2013 
2014         if (p.p_flag & SSYS) {
2015                 mdb_warn("'%s' is a system process\n", p.p_user.u_comm);
2016                 return (DCMD_ERR);
2017         }
2018 
2019         if (mdb_ctf_vread(&pid, "struct pid", "mdb_pid_t", p.p_pidp, 0)
2020             == -1) {
2021                 return (DCMD_ERR);
2022         }
2023 
2024         if ((P = Pgrab_ops(pid.pid_id, &p, &Pgcore_ops, PGRAB_INCORE)) ==
2025             NULL) {
2026                 mdb_warn("Failed to initialize proc handle");
2027                 return (DCMD_ERR);
2028         }
2029 
2030         (void) snprintf(core_name, sizeof (core_name), "core.%s.%d",
2031             p.p_user.u_comm, pid.pid_id);
2032 
2033         if ((error = Pgcore(P, core_name, CC_CONTENT_DEFAULT)) != 0) {
2034                 mdb_warn("Failed to generate core file: %d", error);
2035                 Pfree(P);
2036                 return (DCMD_ERR);
2037         }
2038 
2039         Pfree(P);
2040         mdb_printf("Created core file: %s\n", core_name);
2041 
2042         return (0);
2043 }
2044 
2045 void
2046 gcore_init(void)
2047 {
2048         GElf_Sym        sym;
2049         uintptr_t       priv_info_addr;
2050 
2051         if (mdb_lookup_by_name("segvn_ops", &sym) == -1) {
2052                 mdb_warn("Failed to lookup symbol 'segvn_ops'\n");
2053                 return;
2054         }
2055         gcore_segvn_ops = sym.st_value;
2056 
2057         if (mdb_readvar(&priv_info_addr, "priv_info") == -1) {
2058                 mdb_warn("Failed to read variable 'priv_info'\n");
2059                 return;
2060         }
2061 
2062         if (mdb_vread(&prinfo, sizeof (prinfo), priv_info_addr) == -1) {
2063                 mdb_warn("Failed to read prinfo from %p\n", priv_info_addr);
2064                 return;
2065         }
2066 
2067         if (mdb_lookup_by_name("sclass", &sym) == -1) {
2068                 mdb_warn("Failed to lookup symbol 'segvn_ops'\n");
2069                 return;
2070         }
2071 
2072         gcore_sclass = mdb_zalloc(sym.st_size, UM_SLEEP);
2073         if (mdb_vread(gcore_sclass, sym.st_size, sym.st_value) != sym.st_size) {
2074                 mdb_warn("Failed to read sclass' from %p\n", sym.st_value);
2075                 return;
2076         }
2077 
2078         if (mdb_lookup_by_name("kas", &sym) == -1) {
2079                 mdb_warn("Failed to lookup symbol 'kas'\n");
2080                 return;
2081         }
2082         gcore_kas = sym.st_value;
2083 
2084         gcore_initialized = B_TRUE;
2085 }
2086 
2087 #endif /* _KMDB */