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 != NULL) {
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_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 == NULL) {
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 = NULL;
879 uintptr_t t_onproc = NULL; // running on processor
880 uintptr_t t_run = NULL; // runnable, on disp queue
881 uintptr_t t_sleep = NULL; // sleeping
882 uintptr_t t_susp = NULL; // suspended stop
883 uintptr_t t_jstop = NULL; // jobcontrol stop, w/o directed stop
884 uintptr_t t_jdstop = NULL; // jobcontrol stop with directed stop
885 uintptr_t t_req = NULL; // requested stop
886 uintptr_t t_istop = NULL; // event-of-interest stop
887 uintptr_t t_dtrace = NULL; // DTrace stop
888
889 /*
890 * If the agent lwp exists, it takes precedence over all others.
891 */
892 if ((t_addr = p->p_agenttp) != NULL) {
893 return (t_addr);
894 }
895
896 if ((t_addr = p->p_tlist) == NULL) /* 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 == NULL)
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 == NULL)
915 t_sleep = t_addr;
916 break;
917 case TS_RUN:
918 case TS_WAIT:
919 if (t_run == NULL)
920 t_run = t_addr;
921 break;
922 case TS_ONPROC:
923 if (t_onproc == NULL)
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 == NULL)
936 t_susp = t_addr;
937 break;
938 case PR_JOBCONTROL:
939 if (t->t_proc_flag & TP_PRSTOP) {
940 if (t_jdstop == NULL)
941 t_jdstop = t_addr;
942 } else {
943 if (t_jstop == NULL)
944 t_jstop = t_addr;
945 }
946 break;
947 case PR_REQUESTED:
948 if (t->t_dtrace_stop && t_dtrace == NULL)
949 t_dtrace = t_addr;
950 else if (t_req == NULL)
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 == NULL ||
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 == NULL) {
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 for (i = 0, auxp = up->u_auxv;
1301 i < sizeof (up->u_auxv) / sizeof (up->u_auxv[0]);
1302 i++, auxp++) {
1303 if (auxp->a_type == AT_SUN_EXECNAME) {
1304 sp->pr_sysarg[0] =
1305 (uintptr_t)auxp->a_un.a_ptr;
1306 break;
1307 }
1308 }
1309 }
1310 }
1311 return (0);
1312 }
1313
1314 static int
gcore_lstatus_cb(mdb_proc_t * p,lwpent_t * lwent,void * data)1315 gcore_lstatus_cb(mdb_proc_t *p, lwpent_t *lwent, void *data)
1316 {
1317 lwpstatus_t *lstatus = data;
1318 uintptr_t t_addr = (uintptr_t)lwent->le_thread;
1319 mdb_kthread_t kthrd;
1320
1321 if (t_addr == NULL) {
1322 return (1);
1323 }
1324
1325 if (mdb_ctf_vread(&kthrd, "kthread_t", "mdb_kthread_t", t_addr, 0)
1326 == -1) {
1327 return (-1);
1328 }
1329
1330 return (gcore_prgetlwpstatus(p, t_addr, &kthrd, lstatus, NULL));
1331 }
1332
1333 static prheader_t *
gcore_walk_lwps(mdb_proc_t * p,lwp_callback_t callback,int nlwp,size_t ent_size)1334 gcore_walk_lwps(mdb_proc_t *p, lwp_callback_t callback, int nlwp,
1335 size_t ent_size)
1336 {
1337 void *ent;
1338 prheader_t *php;
1339 lwpdir_t *ldp;
1340 lwpdir_t ld;
1341 lwpent_t lwent;
1342 int status;
1343 int i;
1344
1345 php = calloc(1, sizeof (prheader_t) + nlwp * ent_size);
1346 if (php == NULL) {
1347 return (NULL);
1348 }
1349 php->pr_nent = nlwp;
1350 php->pr_entsize = ent_size;
1351
1352 ent = php + 1;
1353 for (ldp = (lwpdir_t *)p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++,
1354 ldp++) {
1355 if (mdb_vread(&ld, sizeof (ld), (uintptr_t)ldp) !=
1356 sizeof (ld)) {
1357 mdb_warn("Failed to read lwpdir_t from %p\n", ldp);
1358 goto error;
1359 }
1360
1361 if (ld.ld_entry == NULL) {
1362 continue;
1363 }
1364
1365 if (mdb_vread(&lwent, sizeof (lwent), (uintptr_t)ld.ld_entry) !=
1366 sizeof (lwent)) {
1367 mdb_warn("Failed to read lwpent_t from %p\n",
1368 ld.ld_entry);
1369 goto error;
1370 }
1371
1372 status = callback(p, &lwent, ent);
1373 if (status == -1) {
1374 dprintf("lwp callback %p returned -1\n", callback);
1375 goto error;
1376 }
1377 if (status == 1) {
1378 dprintf("lwp callback %p returned 1\n", callback);
1379 continue;
1380 }
1381
1382 ent = (caddr_t)ent + ent_size;
1383 }
1384
1385 return (php);
1386
1387 error:
1388 free(php);
1389 return (NULL);
1390 }
1391
1392 /*
1393 * Misc helper functions.
1394 */
1395 /*
1396 * convert code/data pair into old style wait status
1397 */
1398 static int
gcore_wstat(int code,int data)1399 gcore_wstat(int code, int data)
1400 {
1401 int stat = (data & 0377);
1402
1403 switch (code) {
1404 case CLD_EXITED:
1405 stat <<= 8;
1406 break;
1407 case CLD_DUMPED:
1408 stat |= WCOREFLG;
1409 break;
1410 case CLD_KILLED:
1411 break;
1412 case CLD_TRAPPED:
1413 case CLD_STOPPED:
1414 stat <<= 8;
1415 stat |= WSTOPFLG;
1416 break;
1417 case CLD_CONTINUED:
1418 stat = WCONTFLG;
1419 break;
1420 default:
1421 mdb_warn("wstat: bad code %d\n", code);
1422 }
1423 return (stat);
1424 }
1425
1426 #if defined(__i386) || defined(__amd64)
1427 static void
gcore_usd_to_ssd(user_desc_t * usd,struct ssd * ssd,selector_t sel)1428 gcore_usd_to_ssd(user_desc_t *usd, struct ssd *ssd, selector_t sel)
1429 {
1430 ssd->bo = USEGD_GETBASE(usd);
1431 ssd->ls = USEGD_GETLIMIT(usd);
1432 ssd->sel = sel;
1433
1434 /*
1435 * set type, dpl and present bits.
1436 */
1437 ssd->acc1 = usd->usd_type;
1438 ssd->acc1 |= usd->usd_dpl << 5;
1439 ssd->acc1 |= usd->usd_p << (5 + 2);
1440
1441 /*
1442 * set avl, DB and granularity bits.
1443 */
1444 ssd->acc2 = usd->usd_avl;
1445
1446 #if defined(__amd64)
1447 ssd->acc2 |= usd->usd_long << 1;
1448 #else
1449 ssd->acc2 |= usd->usd_reserved << 1;
1450 #endif
1451
1452 ssd->acc2 |= usd->usd_def32 << (1 + 1);
1453 ssd->acc2 |= usd->usd_gran << (1 + 1 + 1);
1454 }
1455 #endif
1456
1457 static priv_set_t *
gcore_priv_getset(cred_t * cr,int set)1458 gcore_priv_getset(cred_t *cr, int set)
1459 {
1460 if ((CR_FLAGS(cr) & PRIV_AWARE) == 0) {
1461 switch (set) {
1462 case PRIV_EFFECTIVE:
1463 return (&CR_OEPRIV(cr));
1464 case PRIV_PERMITTED:
1465 return (&CR_OPPRIV(cr));
1466 }
1467 }
1468 return (&CR_PRIVS(cr)->crprivs[set]);
1469 }
1470
1471 static void
gcore_priv_getinfo(const cred_t * cr,void * buf)1472 gcore_priv_getinfo(const cred_t *cr, void *buf)
1473 {
1474 struct priv_info_uint *ii;
1475
1476 ii = buf;
1477 ii->val = CR_FLAGS(cr);
1478 ii->info.priv_info_size = (uint32_t)sizeof (*ii);
1479 ii->info.priv_info_type = PRIV_INFO_FLAGS;
1480 }
1481
1482 static void
map_list_free(prmap_node_t * n)1483 map_list_free(prmap_node_t *n)
1484 {
1485 prmap_node_t *next;
1486
1487 while (n != NULL) {
1488 next = n->next;
1489 mdb_free(n, sizeof (*n));
1490 n = next;
1491 }
1492 }
1493
1494 /*
1495 * Ops vector functions for ::gcore.
1496 */
1497 /*ARGSUSED*/
1498 static ssize_t
Pread_gcore(struct ps_prochandle * P,void * buf,size_t n,uintptr_t addr,void * data)1499 Pread_gcore(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr,
1500 void *data)
1501 {
1502 mdb_proc_t *p = data;
1503 ssize_t ret;
1504
1505 ret = mdb_aread(buf, n, addr, (void *)p->p_as);
1506 if (ret != n) {
1507 dprintf("%s: addr: %p len: %llx\n", __func__, addr, n);
1508 (void) memset(buf, 0, n);
1509 return (n);
1510 }
1511
1512 return (ret);
1513 }
1514
1515 /*ARGSUSED*/
1516 static ssize_t
Pwrite_gcore(struct ps_prochandle * P,const void * buf,size_t n,uintptr_t addr,void * data)1517 Pwrite_gcore(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr,
1518 void *data)
1519 {
1520 dprintf("%s: addr: %p len: %llx\n", __func__, addr, n);
1521
1522 return (-1);
1523 }
1524
1525 /*ARGSUSED*/
1526 static int
Pread_maps_gcore(struct ps_prochandle * P,prmap_t ** Pmapp,ssize_t * nmapp,void * data)1527 Pread_maps_gcore(struct ps_prochandle *P, prmap_t **Pmapp, ssize_t *nmapp,
1528 void *data)
1529 {
1530 mdb_proc_t *p = data;
1531 read_maps_cbarg_t cbarg;
1532 prmap_node_t *n;
1533 prmap_t *pmap;
1534 uintptr_t segtree_addr;
1535 int error;
1536 int i;
1537
1538 cbarg.p = p;
1539 cbarg.brkseg = gcore_break_seg(p);
1540 cbarg.stkseg = gcore_as_segat(p->p_as, gcore_prgetstackbase(p));
1541
1542 (void) memset(&cbarg, 0, sizeof (cbarg));
1543 segtree_addr = p->p_as + mdb_ctf_offsetof_by_name("struct as",
1544 "a_segtree");
1545 error = avl_walk_mdb(segtree_addr, read_maps_cb, &cbarg);
1546 if (error != WALK_DONE) {
1547 return (-1);
1548 }
1549
1550 /* Conver the linked list into an array */
1551 pmap = malloc(cbarg.map_len * sizeof (*pmap));
1552 if (pmap == NULL) {
1553 map_list_free(cbarg.map_head);
1554 return (-1);
1555 }
1556
1557 for (i = 0, n = cbarg.map_head; i < cbarg.map_len; i++, n = n->next) {
1558 (void) memcpy(&pmap[i], &n->m, sizeof (prmap_t));
1559 }
1560 map_list_free(cbarg.map_head);
1561
1562 for (i = 0; i < cbarg.map_len; i++) {
1563 dprintf("pr_vaddr: %p pr_size: %llx, pr_name: %s "
1564 "pr_offset: %p pr_mflags: 0x%x\n",
1565 pmap[i].pr_vaddr, pmap[i].pr_size,
1566 pmap[i].pr_mapname, pmap[i].pr_offset,
1567 pmap[i].pr_mflags);
1568 }
1569
1570 *Pmapp = pmap;
1571 *nmapp = cbarg.map_len;
1572
1573 return (0);
1574 }
1575
1576 /*ARGSUSED*/
1577 static void
Pread_aux_gcore(struct ps_prochandle * P,auxv_t ** auxvp,int * nauxp,void * data)1578 Pread_aux_gcore(struct ps_prochandle *P, auxv_t **auxvp, int *nauxp, void *data)
1579 {
1580 mdb_proc_t *p = data;
1581 auxv_t *auxv;
1582 int naux;
1583
1584 naux = __KERN_NAUXV_IMPL;
1585 auxv = calloc(naux + 1, sizeof (*auxv));
1586 if (auxv == NULL) {
1587 *auxvp = NULL;
1588 *nauxp = 0;
1589 return;
1590 }
1591
1592 (void) memcpy(auxv, p->p_user.u_auxv, naux * sizeof (*auxv));
1593
1594 *auxvp = auxv;
1595 *nauxp = naux;
1596 }
1597
1598 /*ARGSUSED*/
1599 static int
Pcred_gcore(struct ps_prochandle * P,prcred_t * prcp,int ngroups,void * data)1600 Pcred_gcore(struct ps_prochandle *P, prcred_t *prcp, int ngroups, void *data)
1601 {
1602 mdb_proc_t *p = data;
1603 cred_t cr;
1604 credgrp_t crgrp;
1605 int i;
1606
1607 if (mdb_vread(&cr, sizeof (cr), p->p_cred) != sizeof (cr)) {
1608 mdb_warn("Failed to read cred_t from %p\n", p->p_cred);
1609 return (-1);
1610 }
1611
1612 prcp->pr_euid = cr.cr_uid;
1613 prcp->pr_ruid = cr.cr_ruid;
1614 prcp->pr_suid = cr.cr_suid;
1615 prcp->pr_egid = cr.cr_gid;
1616 prcp->pr_rgid = cr.cr_rgid;
1617 prcp->pr_sgid = cr.cr_sgid;
1618
1619 if (cr.cr_grps == 0) {
1620 prcp->pr_ngroups = 0;
1621 return (0);
1622 }
1623
1624 if (mdb_vread(&crgrp, sizeof (crgrp), (uintptr_t)cr.cr_grps) !=
1625 sizeof (crgrp)) {
1626 mdb_warn("Failed to read credgrp_t from %p\n", cr.cr_grps);
1627 return (-1);
1628 }
1629
1630 prcp->pr_ngroups = MIN(ngroups, crgrp.crg_ngroups);
1631 for (i = 0; i < prcp->pr_ngroups; i++) {
1632 prcp->pr_groups[i] = crgrp.crg_groups[i];
1633 }
1634
1635 return (0);
1636 }
1637
1638 /*ARGSUSED*/
1639 static int
Ppriv_gcore(struct ps_prochandle * P,prpriv_t ** pprv,void * data)1640 Ppriv_gcore(struct ps_prochandle *P, prpriv_t **pprv, void *data)
1641 {
1642 mdb_proc_t *p = data;
1643 prpriv_t *pp;
1644 cred_t cr;
1645 priv_set_t *psa;
1646 size_t pprv_size;
1647 int i;
1648
1649 pprv_size = sizeof (prpriv_t) + PRIV_SETBYTES - sizeof (priv_chunk_t) +
1650 prinfo.priv_infosize;
1651
1652 pp = malloc(pprv_size);
1653 if (pp == NULL) {
1654 return (-1);
1655 }
1656
1657 if (mdb_vread(&cr, sizeof (cr), p->p_cred) != sizeof (cr)) {
1658 mdb_warn("Failed to read cred_t from %p\n", p->p_cred);
1659 free(pp);
1660 return (-1);
1661 }
1662
1663 pp->pr_nsets = PRIV_NSET;
1664 pp->pr_setsize = PRIV_SETSIZE;
1665 pp->pr_infosize = prinfo.priv_infosize;
1666
1667 psa = (priv_set_t *)pp->pr_sets;
1668 for (i = 0; i < PRIV_NSET; i++) {
1669 psa[i] = *gcore_priv_getset(&cr, i);
1670 }
1671
1672 gcore_priv_getinfo(&cr, (char *)pp + PRIV_PRPRIV_INFO_OFFSET(pp));
1673
1674 *pprv = pp;
1675 return (0);
1676 }
1677
1678 /*
1679 * Fields not filled populated:
1680 * - pr_utime
1681 * - pr_stkbase
1682 * - pr_cutime
1683 * - pr_cstime
1684 * - pr_agentid
1685 */
1686 /*ARGSUSED*/
1687 static void
Pstatus_gcore(struct ps_prochandle * P,pstatus_t * sp,void * data)1688 Pstatus_gcore(struct ps_prochandle *P, pstatus_t *sp, void *data)
1689 {
1690 mdb_proc_t *p = data;
1691 uintptr_t t_addr;
1692 mdb_kthread_t kthr;
1693 mdb_kthread_t *t;
1694 pcommon_t pc;
1695
1696 t_addr = gcore_prchoose(p);
1697 if (t_addr != NULL) {
1698 if (mdb_ctf_vread(&kthr, "kthread_t", "mdb_kthread_t", t_addr,
1699 0) == -1) {
1700 return;
1701 }
1702 t = &kthr;
1703 }
1704
1705 /* just bzero the process part, prgetlwpstatus() does the rest */
1706 bzero(sp, sizeof (pstatus_t) - sizeof (lwpstatus_t));
1707
1708 if (pcommon_init(p, &pc) == -1) {
1709 return;
1710 }
1711 sp->pr_nlwp = pc.pc_nlwp;
1712 sp->pr_nzomb = pc.pc_nzomb;
1713 sp->pr_pid = pc.pc_pid;
1714 sp->pr_ppid = pc.pc_ppid;
1715 sp->pr_pgid = pc.pc_pgid;
1716 sp->pr_sid = pc.pc_sid;
1717 sp->pr_taskid = pc.pc_taskid;
1718 sp->pr_projid = pc.pc_projid;
1719 sp->pr_zoneid = pc.pc_zoneid;
1720 sp->pr_dmodel = pc.pc_dmodel;
1721
1722 prassignset(&sp->pr_sigpend, &p->p_sig);
1723 sp->pr_brkbase = p->p_brkbase;
1724 sp->pr_brksize = p->p_brksize;
1725 sp->pr_stkbase = gcore_prgetstackbase(p);
1726 sp->pr_stksize = p->p_stksize;
1727
1728 prassignset(&sp->pr_sigtrace, &p->p_sigmask);
1729 prassignset(&sp->pr_flttrace, &p->p_fltmask);
1730 prassignset(&sp->pr_sysentry, &PTOU(p)->u_entrymask);
1731 prassignset(&sp->pr_sysexit, &PTOU(p)->u_exitmask);
1732
1733 /* get the chosen lwp's status */
1734 gcore_prgetlwpstatus(p, t_addr, t, &sp->pr_lwp, NULL);
1735
1736 /* replicate the flags */
1737 sp->pr_flags = sp->pr_lwp.pr_flags;
1738 }
1739
1740 /*
1741 * Fields not populated:
1742 * - pr_contract
1743 * - pr_addr
1744 * - pr_rtime
1745 * - pr_ctime
1746 * - pr_ttydev
1747 * - pr_pctcpu
1748 * - pr_size
1749 * - pr_rsize
1750 * - pr_pctmem
1751 */
1752 /*ARGSUSED*/
1753 static const psinfo_t *
Ppsinfo_gcore(struct ps_prochandle * P,psinfo_t * psp,void * data)1754 Ppsinfo_gcore(struct ps_prochandle *P, psinfo_t *psp, void *data)
1755 {
1756 mdb_proc_t *p = data;
1757 mdb_kthread_t *t;
1758 mdb_pool_t pool;
1759 cred_t cr;
1760 uintptr_t t_addr;
1761 pcommon_t pc;
1762
1763 if ((t_addr = gcore_prchoose(p)) == NULL) {
1764 bzero(psp, sizeof (*psp));
1765 } else {
1766 bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
1767 }
1768
1769 if (pcommon_init(p, &pc) == -1) {
1770 return (NULL);
1771 }
1772 psp->pr_nlwp = pc.pc_nlwp;
1773 psp->pr_nzomb = pc.pc_nzomb;
1774 psp->pr_pid = pc.pc_pid;
1775 psp->pr_ppid = pc.pc_ppid;
1776 psp->pr_pgid = pc.pc_pgid;
1777 psp->pr_sid = pc.pc_sid;
1778 psp->pr_taskid = pc.pc_taskid;
1779 psp->pr_projid = pc.pc_projid;
1780 psp->pr_dmodel = pc.pc_dmodel;
1781
1782 /*
1783 * only export SSYS and SMSACCT; everything else is off-limits to
1784 * userland apps.
1785 */
1786 psp->pr_flag = p->p_flag & (SSYS | SMSACCT);
1787
1788 if (mdb_vread(&cr, sizeof (cr), p->p_cred) != sizeof (cr)) {
1789 mdb_warn("Failed to read cred_t from %p\n", p->p_cred);
1790 return (NULL);
1791 }
1792
1793 psp->pr_uid = cr.cr_ruid;
1794 psp->pr_euid = cr.cr_uid;
1795 psp->pr_gid = cr.cr_rgid;
1796 psp->pr_egid = cr.cr_gid;
1797
1798 if (mdb_ctf_vread(&pool, "pool_t", "mdb_pool_t", p->p_pool, 0) == -1) {
1799 return (NULL);
1800 }
1801 psp->pr_poolid = pool.pool_id;
1802
1803 if (t_addr == 0) {
1804 int wcode = p->p_wcode;
1805
1806 if (wcode)
1807 psp->pr_wstat = gcore_wstat(wcode, p->p_wdata);
1808 psp->pr_ttydev = PRNODEV;
1809 psp->pr_lwp.pr_state = SZOMB;
1810 psp->pr_lwp.pr_sname = 'Z';
1811 psp->pr_lwp.pr_bindpro = PBIND_NONE;
1812 psp->pr_lwp.pr_bindpset = PS_NONE;
1813 } else {
1814 mdb_kthread_t kthr;
1815 user_t *up = PTOU(p);
1816
1817 psp->pr_start = up->u_start;
1818 bcopy(up->u_comm, psp->pr_fname,
1819 MIN(sizeof (up->u_comm), sizeof (psp->pr_fname)-1));
1820 bcopy(up->u_psargs, psp->pr_psargs,
1821 MIN(PRARGSZ-1, PSARGSZ));
1822
1823 psp->pr_argc = up->u_argc;
1824 psp->pr_argv = up->u_argv;
1825 psp->pr_envp = up->u_envp;
1826
1827 /* get the chosen lwp's lwpsinfo */
1828 if (mdb_ctf_vread(&kthr, "kthread_t", "mdb_kthread_t", t_addr,
1829 0) == -1) {
1830 return (NULL);
1831 }
1832 t = &kthr;
1833
1834 gcore_prgetlwpsinfo(t_addr, t, &psp->pr_lwp);
1835 }
1836
1837 return (NULL);
1838 }
1839
1840 /*ARGSUSED*/
1841 static prheader_t *
Plstatus_gcore(struct ps_prochandle * P,void * data)1842 Plstatus_gcore(struct ps_prochandle *P, void *data)
1843 {
1844 mdb_proc_t *p = data;
1845 int nlwp = p->p_lwpcnt;
1846 size_t ent_size = LSPAN(lwpstatus_t);
1847
1848 return (gcore_walk_lwps(p, gcore_lstatus_cb, nlwp, ent_size));
1849 }
1850
1851 /*ARGSUSED*/
1852 static prheader_t *
Plpsinfo_gcore(struct ps_prochandle * P,void * data)1853 Plpsinfo_gcore(struct ps_prochandle *P, void *data)
1854 {
1855 mdb_proc_t *p = data;
1856 int nlwp = p->p_lwpcnt + p->p_zombcnt;
1857 size_t ent_size = LSPAN(lwpsinfo_t);
1858
1859 return (gcore_walk_lwps(p, gcore_lpsinfo_cb, nlwp, ent_size));
1860 }
1861
1862 /*ARGSUSED*/
1863 static char *
Pplatform_gcore(struct ps_prochandle * P,char * s,size_t n,void * data)1864 Pplatform_gcore(struct ps_prochandle *P, char *s, size_t n, void *data)
1865 {
1866 char platform[SYS_NMLN];
1867
1868 if (mdb_readvar(platform, "platform") == -1) {
1869 mdb_warn("failed to read platform!\n");
1870 return (NULL);
1871 }
1872 dprintf("platform: %s\n", platform);
1873
1874 (void) strncpy(s, platform, n);
1875 return (s);
1876 }
1877
1878 /*ARGSUSED*/
1879 static int
Puname_gcore(struct ps_prochandle * P,struct utsname * u,void * data)1880 Puname_gcore(struct ps_prochandle *P, struct utsname *u, void *data)
1881 {
1882 if (mdb_readvar(u, "utsname") != sizeof (*u)) {
1883 return (-1);
1884 }
1885
1886 return (0);
1887 }
1888
1889 /*ARGSUSED*/
1890 static char *
Pzonename_gcore(struct ps_prochandle * P,char * s,size_t n,void * data)1891 Pzonename_gcore(struct ps_prochandle *P, char *s, size_t n, void *data)
1892 {
1893 mdb_proc_t *p = data;
1894 mdb_zone_t zone;
1895
1896 if (mdb_ctf_vread(&zone, "zone_t", "mdb_zone_t", p->p_zone, 0) == -1) {
1897 return (NULL);
1898 }
1899
1900 if (mdb_readstr(s, n, zone.zone_name) == -1) {
1901 mdb_warn("Failed to read zone name from %p\n", zone.zone_name);
1902 return (NULL);
1903 }
1904
1905 return (s);
1906 }
1907
1908 /*ARGSUSED*/
1909 static char *
Pexecname_gcore(struct ps_prochandle * P,char * buf,size_t buflen,void * data)1910 Pexecname_gcore(struct ps_prochandle *P, char *buf, size_t buflen, void *data)
1911 {
1912 mdb_proc_t *p = data;
1913 mdb_vnode_t vn;
1914
1915 if (mdb_ctf_vread(&vn, "vnode_t", "mdb_vnode_t", p->p_exec, 0) == -1) {
1916 return (NULL);
1917 }
1918
1919 if (mdb_readstr(buf, buflen, vn.v_path) == -1) {
1920 mdb_warn("Failed to read vnode path from %p\n", vn.v_path);
1921 return (NULL);
1922 }
1923
1924 dprintf("execname: %s\n", buf);
1925
1926 return (buf);
1927 }
1928
1929 #if defined(__i386) || defined(__amd64)
1930 /*ARGSUSED*/
1931 static int
Pldt_gcore(struct ps_prochandle * P,struct ssd * pldt,int nldt,void * data)1932 Pldt_gcore(struct ps_prochandle *P, struct ssd *pldt, int nldt, void *data)
1933 {
1934 mdb_proc_t *p = data;
1935 user_desc_t *udp;
1936 user_desc_t *ldts;
1937 size_t ldt_size;
1938 int i, limit;
1939
1940 if (p->p_ldt == NULL) {
1941 return (0);
1942 }
1943
1944 limit = p->p_ldtlimit;
1945
1946 /* Is this call just to query the size ? */
1947 if (pldt == NULL || nldt == 0) {
1948 return (limit);
1949 }
1950
1951 ldt_size = limit * sizeof (*ldts);
1952 ldts = malloc(ldt_size);
1953 if (ldts == NULL) {
1954 mdb_warn("Failed to malloc ldts (size %lld)n", ldt_size);
1955 return (-1);
1956 }
1957
1958 if (mdb_vread(ldts, ldt_size, p->p_ldt) != ldt_size) {
1959 mdb_warn("Failed to read ldts from %p\n", p->p_ldt);
1960 free(ldts);
1961 return (-1);
1962 }
1963
1964 for (i = LDT_UDBASE, udp = &ldts[i]; i <= limit; i++, udp++) {
1965 if (udp->usd_type != 0 || udp->usd_dpl != 0 ||
1966 udp->usd_p != 0) {
1967 gcore_usd_to_ssd(udp, pldt++, SEL_LDT(i));
1968 }
1969 }
1970
1971 free(ldts);
1972 return (limit);
1973 }
1974 #endif
1975
1976 static const ps_ops_t Pgcore_ops = {
1977 .pop_pread = Pread_gcore,
1978 .pop_pwrite = Pwrite_gcore,
1979 .pop_read_maps = Pread_maps_gcore,
1980 .pop_read_aux = Pread_aux_gcore,
1981 .pop_cred = Pcred_gcore,
1982 .pop_priv = Ppriv_gcore,
1983 .pop_psinfo = Ppsinfo_gcore,
1984 .pop_status = Pstatus_gcore,
1985 .pop_lstatus = Plstatus_gcore,
1986 .pop_lpsinfo = Plpsinfo_gcore,
1987 .pop_platform = Pplatform_gcore,
1988 .pop_uname = Puname_gcore,
1989 .pop_zonename = Pzonename_gcore,
1990 .pop_execname = Pexecname_gcore,
1991 #if defined(__i386) || defined(__amd64)
1992 .pop_ldt = Pldt_gcore
1993 #endif
1994 };
1995
1996 /*ARGSUSED*/
1997 int
gcore_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1998 gcore_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1999 {
2000 struct ps_prochandle *P;
2001 char core_name[MAXNAMELEN];
2002 mdb_proc_t p;
2003 mdb_pid_t pid;
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 (Pgcore(P, core_name, CC_CONTENT_DEFAULT) != 0) {
2034 mdb_warn("Failed to generate core file: %d", errno);
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
gcore_init(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