xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/gcore.c (revision 69a119caa6570c7077699161b7c28b6ee9f8b0f4)
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 */
2088