xref: /onnv-gate/usr/src/cmd/mdb/common/modules/libumem/libumem.c (revision 10610:218c21980cfd)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51528Sjwadams  * Common Development and Distribution License (the "License").
61528Sjwadams  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*10388SJonathan.Adams@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include "umem.h"
270Sstevel@tonic-gate #include <libproc.h>
280Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include "kgrep.h"
310Sstevel@tonic-gate #include "leaky.h"
320Sstevel@tonic-gate #include "misc.h"
330Sstevel@tonic-gate #include "proc_kludges.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <umem_impl.h>
360Sstevel@tonic-gate #include <sys/vmem_impl_user.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include "umem_pagesize.h"
390Sstevel@tonic-gate 
400Sstevel@tonic-gate typedef struct datafmt {
410Sstevel@tonic-gate 	char	*hdr1;
420Sstevel@tonic-gate 	char	*hdr2;
430Sstevel@tonic-gate 	char	*dashes;
440Sstevel@tonic-gate 	char	*fmt;
450Sstevel@tonic-gate } datafmt_t;
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static datafmt_t umemfmt[] = {
480Sstevel@tonic-gate 	{ "cache                    ", "name                     ",
490Sstevel@tonic-gate 	"-------------------------", "%-25s "				},
500Sstevel@tonic-gate 	{ "   buf",	"  size",	"------",	"%6u "		},
510Sstevel@tonic-gate 	{ "   buf",	"in use",	"------",	"%6u "		},
520Sstevel@tonic-gate 	{ "   buf",	" total",	"------",	"%6u "		},
530Sstevel@tonic-gate 	{ "   memory",	"   in use",	"---------",	"%9u "		},
540Sstevel@tonic-gate 	{ "    alloc",	"  succeed",	"---------",	"%9u "		},
550Sstevel@tonic-gate 	{ "alloc",	" fail",	"-----",	"%5llu "	},
560Sstevel@tonic-gate 	{ NULL,		NULL,		NULL,		NULL		}
570Sstevel@tonic-gate };
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static datafmt_t vmemfmt[] = {
600Sstevel@tonic-gate 	{ "vmem                     ", "name                     ",
610Sstevel@tonic-gate 	"-------------------------", "%-*s "				},
620Sstevel@tonic-gate 	{ "   memory",	"   in use",	"---------",	"%9llu "	},
630Sstevel@tonic-gate 	{ "    memory",	"     total",	"----------",	"%10llu "	},
640Sstevel@tonic-gate 	{ "   memory",	"   import",	"---------",	"%9llu "	},
650Sstevel@tonic-gate 	{ "    alloc",	"  succeed",	"---------",	"%9llu "	},
660Sstevel@tonic-gate 	{ "alloc",	" fail",	"-----",	"%5llu "	},
670Sstevel@tonic-gate 	{ NULL,		NULL,		NULL,		NULL		}
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*ARGSUSED*/
710Sstevel@tonic-gate static int
umastat_cpu_avail(uintptr_t addr,const umem_cpu_cache_t * ccp,int * avail)720Sstevel@tonic-gate umastat_cpu_avail(uintptr_t addr, const umem_cpu_cache_t *ccp, int *avail)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	if (ccp->cc_rounds > 0)
750Sstevel@tonic-gate 		*avail += ccp->cc_rounds;
760Sstevel@tonic-gate 	if (ccp->cc_prounds > 0)
770Sstevel@tonic-gate 		*avail += ccp->cc_prounds;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	return (WALK_NEXT);
800Sstevel@tonic-gate }
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /*ARGSUSED*/
830Sstevel@tonic-gate static int
umastat_cpu_alloc(uintptr_t addr,const umem_cpu_cache_t * ccp,int * alloc)840Sstevel@tonic-gate umastat_cpu_alloc(uintptr_t addr, const umem_cpu_cache_t *ccp, int *alloc)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	*alloc += ccp->cc_alloc;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	return (WALK_NEXT);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*ARGSUSED*/
920Sstevel@tonic-gate static int
umastat_slab_avail(uintptr_t addr,const umem_slab_t * sp,int * avail)930Sstevel@tonic-gate umastat_slab_avail(uintptr_t addr, const umem_slab_t *sp, int *avail)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	*avail += sp->slab_chunks - sp->slab_refcnt;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	return (WALK_NEXT);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate typedef struct umastat_vmem {
1010Sstevel@tonic-gate 	uintptr_t kv_addr;
1020Sstevel@tonic-gate 	struct umastat_vmem *kv_next;
1030Sstevel@tonic-gate 	int kv_meminuse;
1040Sstevel@tonic-gate 	int kv_alloc;
1050Sstevel@tonic-gate 	int kv_fail;
1060Sstevel@tonic-gate } umastat_vmem_t;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate static int
umastat_cache(uintptr_t addr,const umem_cache_t * cp,umastat_vmem_t ** kvp)1090Sstevel@tonic-gate umastat_cache(uintptr_t addr, const umem_cache_t *cp, umastat_vmem_t **kvp)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 	umastat_vmem_t *kv;
1120Sstevel@tonic-gate 	datafmt_t *dfp = umemfmt;
1130Sstevel@tonic-gate 	int magsize;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	int avail, alloc, total;
1160Sstevel@tonic-gate 	size_t meminuse = (cp->cache_slab_create - cp->cache_slab_destroy) *
1170Sstevel@tonic-gate 	    cp->cache_slabsize;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	mdb_walk_cb_t cpu_avail = (mdb_walk_cb_t)umastat_cpu_avail;
1200Sstevel@tonic-gate 	mdb_walk_cb_t cpu_alloc = (mdb_walk_cb_t)umastat_cpu_alloc;
1210Sstevel@tonic-gate 	mdb_walk_cb_t slab_avail = (mdb_walk_cb_t)umastat_slab_avail;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	magsize = umem_get_magsize(cp);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	alloc = cp->cache_slab_alloc + cp->cache_full.ml_alloc;
1260Sstevel@tonic-gate 	avail = cp->cache_full.ml_total * magsize;
1270Sstevel@tonic-gate 	total = cp->cache_buftotal;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	(void) mdb_pwalk("umem_cpu_cache", cpu_alloc, &alloc, addr);
1300Sstevel@tonic-gate 	(void) mdb_pwalk("umem_cpu_cache", cpu_avail, &avail, addr);
1310Sstevel@tonic-gate 	(void) mdb_pwalk("umem_slab_partial", slab_avail, &avail, addr);
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	for (kv = *kvp; kv != NULL; kv = kv->kv_next) {
1340Sstevel@tonic-gate 		if (kv->kv_addr == (uintptr_t)cp->cache_arena)
1350Sstevel@tonic-gate 			goto out;
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	kv = mdb_zalloc(sizeof (umastat_vmem_t), UM_SLEEP | UM_GC);
1390Sstevel@tonic-gate 	kv->kv_next = *kvp;
1400Sstevel@tonic-gate 	kv->kv_addr = (uintptr_t)cp->cache_arena;
1410Sstevel@tonic-gate 	*kvp = kv;
1420Sstevel@tonic-gate out:
1430Sstevel@tonic-gate 	kv->kv_meminuse += meminuse;
1440Sstevel@tonic-gate 	kv->kv_alloc += alloc;
1450Sstevel@tonic-gate 	kv->kv_fail += cp->cache_alloc_fail;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, cp->cache_name);
1480Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, cp->cache_bufsize);
1490Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, total - avail);
1500Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, total);
1510Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, meminuse);
1520Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, alloc);
1530Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, cp->cache_alloc_fail);
1540Sstevel@tonic-gate 	mdb_printf("\n");
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	return (WALK_NEXT);
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate static int
umastat_vmem_totals(uintptr_t addr,const vmem_t * v,umastat_vmem_t * kv)1600Sstevel@tonic-gate umastat_vmem_totals(uintptr_t addr, const vmem_t *v, umastat_vmem_t *kv)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate 	while (kv != NULL && kv->kv_addr != addr)
1630Sstevel@tonic-gate 		kv = kv->kv_next;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if (kv == NULL || kv->kv_alloc == 0)
1660Sstevel@tonic-gate 		return (WALK_NEXT);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	mdb_printf("Total [%s]%*s %6s %6s %6s %9u %9u %5u\n", v->vm_name,
1690Sstevel@tonic-gate 	    17 - strlen(v->vm_name), "", "", "", "",
1700Sstevel@tonic-gate 	    kv->kv_meminuse, kv->kv_alloc, kv->kv_fail);
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	return (WALK_NEXT);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /*ARGSUSED*/
1760Sstevel@tonic-gate static int
umastat_vmem(uintptr_t addr,const vmem_t * v,void * ignored)1770Sstevel@tonic-gate umastat_vmem(uintptr_t addr, const vmem_t *v, void *ignored)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	datafmt_t *dfp = vmemfmt;
1800Sstevel@tonic-gate 	uintptr_t paddr;
1810Sstevel@tonic-gate 	vmem_t parent;
1820Sstevel@tonic-gate 	int ident = 0;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	for (paddr = (uintptr_t)v->vm_source; paddr != NULL; ident += 4) {
1850Sstevel@tonic-gate 		if (mdb_vread(&parent, sizeof (parent), paddr) == -1) {
1860Sstevel@tonic-gate 			mdb_warn("couldn't trace %p's ancestry", addr);
1870Sstevel@tonic-gate 			ident = 0;
1880Sstevel@tonic-gate 			break;
1890Sstevel@tonic-gate 		}
1900Sstevel@tonic-gate 		paddr = (uintptr_t)parent.vm_source;
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	mdb_printf("%*s", ident, "");
1940Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, 25 - ident, v->vm_name);
1950Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, v->vm_kstat.vk_mem_inuse);
1960Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, v->vm_kstat.vk_mem_total);
1970Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, v->vm_kstat.vk_mem_import);
1980Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, v->vm_kstat.vk_alloc);
1990Sstevel@tonic-gate 	mdb_printf((dfp++)->fmt, v->vm_kstat.vk_fail);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	mdb_printf("\n");
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	return (WALK_NEXT);
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate /*ARGSUSED*/
2070Sstevel@tonic-gate int
umastat(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2080Sstevel@tonic-gate umastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate 	umastat_vmem_t *kv = NULL;
2110Sstevel@tonic-gate 	datafmt_t *dfp;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if (argc != 0)
2140Sstevel@tonic-gate 		return (DCMD_USAGE);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	for (dfp = umemfmt; dfp->hdr1 != NULL; dfp++)
2170Sstevel@tonic-gate 		mdb_printf("%s ", dfp->hdr1);
2180Sstevel@tonic-gate 	mdb_printf("\n");
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	for (dfp = umemfmt; dfp->hdr1 != NULL; dfp++)
2210Sstevel@tonic-gate 		mdb_printf("%s ", dfp->hdr2);
2220Sstevel@tonic-gate 	mdb_printf("\n");
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	for (dfp = umemfmt; dfp->hdr1 != NULL; dfp++)
2250Sstevel@tonic-gate 		mdb_printf("%s ", dfp->dashes);
2260Sstevel@tonic-gate 	mdb_printf("\n");
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	if (mdb_walk("umem_cache", (mdb_walk_cb_t)umastat_cache, &kv) == -1) {
2290Sstevel@tonic-gate 		mdb_warn("can't walk 'umem_cache'");
2300Sstevel@tonic-gate 		return (DCMD_ERR);
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	for (dfp = umemfmt; dfp->hdr1 != NULL; dfp++)
2340Sstevel@tonic-gate 		mdb_printf("%s ", dfp->dashes);
2350Sstevel@tonic-gate 	mdb_printf("\n");
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (mdb_walk("vmem", (mdb_walk_cb_t)umastat_vmem_totals, kv) == -1) {
2380Sstevel@tonic-gate 		mdb_warn("can't walk 'vmem'");
2390Sstevel@tonic-gate 		return (DCMD_ERR);
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	for (dfp = umemfmt; dfp->hdr1 != NULL; dfp++)
2430Sstevel@tonic-gate 		mdb_printf("%s ", dfp->dashes);
2440Sstevel@tonic-gate 	mdb_printf("\n");
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	mdb_printf("\n");
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2490Sstevel@tonic-gate 		mdb_printf("%s ", dfp->hdr1);
2500Sstevel@tonic-gate 	mdb_printf("\n");
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2530Sstevel@tonic-gate 		mdb_printf("%s ", dfp->hdr2);
2540Sstevel@tonic-gate 	mdb_printf("\n");
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2570Sstevel@tonic-gate 		mdb_printf("%s ", dfp->dashes);
2580Sstevel@tonic-gate 	mdb_printf("\n");
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if (mdb_walk("vmem", (mdb_walk_cb_t)umastat_vmem, NULL) == -1) {
2610Sstevel@tonic-gate 		mdb_warn("can't walk 'vmem'");
2620Sstevel@tonic-gate 		return (DCMD_ERR);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
2660Sstevel@tonic-gate 		mdb_printf("%s ", dfp->dashes);
2670Sstevel@tonic-gate 	mdb_printf("\n");
2680Sstevel@tonic-gate 	return (DCMD_OK);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate  * kmdb doesn't use libproc, and thus doesn't have any prmap_t's to walk.
2730Sstevel@tonic-gate  * We have other ways to grep kmdb's address range.
2740Sstevel@tonic-gate  */
2750Sstevel@tonic-gate #ifndef _KMDB
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate typedef struct ugrep_walk_data {
2780Sstevel@tonic-gate 	kgrep_cb_func *ug_cb;
2790Sstevel@tonic-gate 	void *ug_cbdata;
2800Sstevel@tonic-gate } ugrep_walk_data_t;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate /*ARGSUSED*/
2830Sstevel@tonic-gate int
ugrep_mapping_cb(uintptr_t addr,const void * prm_arg,void * data)2840Sstevel@tonic-gate ugrep_mapping_cb(uintptr_t addr, const void *prm_arg, void *data)
2850Sstevel@tonic-gate {
2860Sstevel@tonic-gate 	ugrep_walk_data_t *ug = data;
2870Sstevel@tonic-gate 	const prmap_t *prm = prm_arg;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	return (ug->ug_cb(prm->pr_vaddr, prm->pr_vaddr + prm->pr_size,
2900Sstevel@tonic-gate 	    ug->ug_cbdata));
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate int
kgrep_subr(kgrep_cb_func * cb,void * cbdata)2940Sstevel@tonic-gate kgrep_subr(kgrep_cb_func *cb, void *cbdata)
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate 	ugrep_walk_data_t ug;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	prockludge_add_walkers();
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	ug.ug_cb = cb;
3010Sstevel@tonic-gate 	ug.ug_cbdata = cbdata;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (mdb_walk(KLUDGE_MAPWALK_NAME, ugrep_mapping_cb, &ug) == -1) {
3040Sstevel@tonic-gate 		mdb_warn("Unable to walk "KLUDGE_MAPWALK_NAME);
3050Sstevel@tonic-gate 		return (DCMD_ERR);
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	prockludge_remove_walkers();
3090Sstevel@tonic-gate 	return (DCMD_OK);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate size_t
kgrep_subr_pagesize(void)3130Sstevel@tonic-gate kgrep_subr_pagesize(void)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate 	return (PAGESIZE);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate #endif /* !_KMDB */
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	/* from libumem.c */
3230Sstevel@tonic-gate 	{ "umastat", NULL, "umem allocator stats", umastat },
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/* from misc.c */
3260Sstevel@tonic-gate 	{ "umem_debug", NULL, "toggle umem dcmd/walk debugging", umem_debug},
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	/* from umem.c */
3290Sstevel@tonic-gate 	{ "umem_status", NULL, "Print umem status and message buffer",
3300Sstevel@tonic-gate 		umem_status },
3310Sstevel@tonic-gate 	{ "allocdby", ":", "given a thread, print its allocated buffers",
3320Sstevel@tonic-gate 		allocdby },
3330Sstevel@tonic-gate 	{ "bufctl", ":[-vh] [-a addr] [-c caller] [-e earliest] [-l latest] "
3340Sstevel@tonic-gate 		"[-t thd]", "print or filter a bufctl", bufctl, bufctl_help },
3350Sstevel@tonic-gate 	{ "bufctl_audit", ":", "print a bufctl_audit", bufctl_audit },
3360Sstevel@tonic-gate 	{ "freedby", ":", "given a thread, print its freed buffers", freedby },
3370Sstevel@tonic-gate 	{ "umalog", "[ fail | slab ]",
3380Sstevel@tonic-gate 	    "display umem transaction log and stack traces", umalog },
3390Sstevel@tonic-gate 	{ "umausers", "[-ef] [cache ...]", "display current medium and large "
3400Sstevel@tonic-gate 		"users of the umem allocator", umausers },
3410Sstevel@tonic-gate 	{ "umem_cache", "?", "print a umem cache", umem_cache },
3420Sstevel@tonic-gate 	{ "umem_log", "?", "dump umem transaction log", umem_log },
3431528Sjwadams 	{ "umem_malloc_dist", "[-dg] [-b maxbins] [-B minbinsize]",
3441528Sjwadams 		"report distribution of outstanding malloc()s",
3451528Sjwadams 		umem_malloc_dist, umem_malloc_dist_help },
3461528Sjwadams 	{ "umem_malloc_info", "?[-dg] [-b maxbins] [-B minbinsize]",
3471528Sjwadams 		"report information about malloc()s by cache",
3481528Sjwadams 		umem_malloc_info, umem_malloc_info_help },
3490Sstevel@tonic-gate 	{ "umem_verify", "?", "check integrity of umem-managed memory",
3500Sstevel@tonic-gate 		umem_verify },
3510Sstevel@tonic-gate 	{ "vmem", "?", "print a vmem_t", vmem },
3520Sstevel@tonic-gate 	{ "vmem_seg", ":[-sv] [-c caller] [-e earliest] [-l latest] "
3530Sstevel@tonic-gate 		"[-m minsize] [-M maxsize] [-t thread] [-T type]",
3540Sstevel@tonic-gate 		"print or filter a vmem_seg", vmem_seg, vmem_seg_help },
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate #ifndef _KMDB
3570Sstevel@tonic-gate 	/* from ../genunix/kgrep.c + libumem.c */
3580Sstevel@tonic-gate 	{ "ugrep", KGREP_USAGE, "search user address space for a pointer",
3591580Sjwadams 	    kgrep, kgrep_help },
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	/* from ../genunix/leaky.c + leaky_subr.c */
3620Sstevel@tonic-gate 	{ "findleaks", FINDLEAKS_USAGE, "search for potential memory leaks",
3630Sstevel@tonic-gate 	    findleaks, findleaks_help },
3640Sstevel@tonic-gate #endif
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	{ NULL }
3670Sstevel@tonic-gate };
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	/* from umem.c */
3720Sstevel@tonic-gate 	{ "allocdby", "given a thread, walk its allocated bufctls",
3730Sstevel@tonic-gate 		allocdby_walk_init, allocdby_walk_step, allocdby_walk_fini },
3740Sstevel@tonic-gate 	{ "bufctl", "walk a umem cache's bufctls",
3750Sstevel@tonic-gate 		bufctl_walk_init, umem_walk_step, umem_walk_fini },
3760Sstevel@tonic-gate 	{ "bufctl_history", "walk the available history of a bufctl",
3770Sstevel@tonic-gate 		bufctl_history_walk_init, bufctl_history_walk_step,
3780Sstevel@tonic-gate 		bufctl_history_walk_fini },
3790Sstevel@tonic-gate 	{ "freectl", "walk a umem cache's free bufctls",
3800Sstevel@tonic-gate 		freectl_walk_init, umem_walk_step, umem_walk_fini },
3810Sstevel@tonic-gate 	{ "freedby", "given a thread, walk its freed bufctls",
3820Sstevel@tonic-gate 		freedby_walk_init, allocdby_walk_step, allocdby_walk_fini },
3830Sstevel@tonic-gate 	{ "freemem", "walk a umem cache's free memory",
3840Sstevel@tonic-gate 		freemem_walk_init, umem_walk_step, umem_walk_fini },
3850Sstevel@tonic-gate 	{ "umem", "walk a umem cache",
3860Sstevel@tonic-gate 		umem_walk_init, umem_walk_step, umem_walk_fini },
3870Sstevel@tonic-gate 	{ "umem_cpu", "walk the umem CPU structures",
3880Sstevel@tonic-gate 		umem_cpu_walk_init, umem_cpu_walk_step, umem_cpu_walk_fini },
3890Sstevel@tonic-gate 	{ "umem_cpu_cache", "given a umem cache, walk its per-CPU caches",
3900Sstevel@tonic-gate 		umem_cpu_cache_walk_init, umem_cpu_cache_walk_step, NULL },
3910Sstevel@tonic-gate 	{ "umem_hash", "given a umem cache, walk its allocated hash table",
3920Sstevel@tonic-gate 		umem_hash_walk_init, umem_hash_walk_step, umem_hash_walk_fini },
3930Sstevel@tonic-gate 	{ "umem_log", "walk the umem transaction log",
3940Sstevel@tonic-gate 		umem_log_walk_init, umem_log_walk_step, umem_log_walk_fini },
3950Sstevel@tonic-gate 	{ "umem_slab", "given a umem cache, walk its slabs",
3960Sstevel@tonic-gate 		umem_slab_walk_init, umem_slab_walk_step, NULL },
3970Sstevel@tonic-gate 	{ "umem_slab_partial",
3980Sstevel@tonic-gate 	    "given a umem cache, walk its partially allocated slabs (min 1)",
3990Sstevel@tonic-gate 		umem_slab_walk_partial_init, umem_slab_walk_step, NULL },
4000Sstevel@tonic-gate 	{ "vmem", "walk vmem structures in pre-fix, depth-first order",
4010Sstevel@tonic-gate 		vmem_walk_init, vmem_walk_step, vmem_walk_fini },
4020Sstevel@tonic-gate 	{ "vmem_alloc", "given a vmem_t, walk its allocated vmem_segs",
4030Sstevel@tonic-gate 		vmem_alloc_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4040Sstevel@tonic-gate 	{ "vmem_free", "given a vmem_t, walk its free vmem_segs",
4050Sstevel@tonic-gate 		vmem_free_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4060Sstevel@tonic-gate 	{ "vmem_postfix", "walk vmem structures in post-fix, depth-first order",
4070Sstevel@tonic-gate 		vmem_walk_init, vmem_postfix_walk_step, vmem_walk_fini },
4080Sstevel@tonic-gate 	{ "vmem_seg", "given a vmem_t, walk all of its vmem_segs",
4090Sstevel@tonic-gate 		vmem_seg_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4100Sstevel@tonic-gate 	{ "vmem_span", "given a vmem_t, walk its spanning vmem_segs",
4110Sstevel@tonic-gate 		vmem_span_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate #ifndef _KMDB
4140Sstevel@tonic-gate 	/* from ../genunix/leaky.c + leaky_subr.c */
4150Sstevel@tonic-gate 	{ "leak", "given a leak ctl, walk other leaks w/ that stacktrace",
4160Sstevel@tonic-gate 		leaky_walk_init, leaky_walk_step, leaky_walk_fini },
4170Sstevel@tonic-gate 	{ "leakbuf", "given a leak ctl, walk addr of leaks w/ that stacktrace",
4180Sstevel@tonic-gate 		leaky_walk_init, leaky_buf_walk_step, leaky_walk_fini },
4190Sstevel@tonic-gate #endif
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	{ NULL }
4220Sstevel@tonic-gate };
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate static const mdb_modinfo_t modinfo = {MDB_API_VERSION, dcmds, walkers};
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate const mdb_modinfo_t *
_mdb_init(void)4270Sstevel@tonic-gate _mdb_init(void)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	if (umem_init() != 0)
4300Sstevel@tonic-gate 		return (NULL);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	return (&modinfo);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate void
_mdb_fini(void)4360Sstevel@tonic-gate _mdb_fini(void)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate #ifndef _KMDB
4390Sstevel@tonic-gate 	leaky_cleanup(1);
4400Sstevel@tonic-gate #endif
4410Sstevel@tonic-gate }
442