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