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