17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
287c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
297c478bd9Sstevel@tonic-gate #include <sys/proc.h>
307c478bd9Sstevel@tonic-gate #include <sys/task.h>
317c478bd9Sstevel@tonic-gate #include <sys/project.h>
327c478bd9Sstevel@tonic-gate #include <sys/zone.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate static int
print_val(uintptr_t addr,rctl_val_t * val,uintptr_t * enforced)357c478bd9Sstevel@tonic-gate print_val(uintptr_t addr, rctl_val_t *val, uintptr_t *enforced)
367c478bd9Sstevel@tonic-gate {
377c478bd9Sstevel@tonic-gate 	char *priv;
387c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t val_localflag_bits[] = {
397c478bd9Sstevel@tonic-gate 		{ "SIGNAL", RCTL_LOCAL_SIGNAL, RCTL_LOCAL_SIGNAL },
407c478bd9Sstevel@tonic-gate 		{ "DENY", RCTL_LOCAL_DENY, RCTL_LOCAL_DENY },
417c478bd9Sstevel@tonic-gate 		{ "MAX", RCTL_LOCAL_MAXIMAL, RCTL_LOCAL_MAXIMAL },
427c478bd9Sstevel@tonic-gate 		{ NULL, 0, 0 }
437c478bd9Sstevel@tonic-gate 	};
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate 	switch (val->rcv_privilege) {
467c478bd9Sstevel@tonic-gate 	case (RCPRIV_BASIC):
477c478bd9Sstevel@tonic-gate 		priv = "basic";
487c478bd9Sstevel@tonic-gate 		break;
497c478bd9Sstevel@tonic-gate 	case (RCPRIV_PRIVILEGED):
507c478bd9Sstevel@tonic-gate 		priv = "privileged";
517c478bd9Sstevel@tonic-gate 		break;
527c478bd9Sstevel@tonic-gate 	case (RCPRIV_SYSTEM):
537c478bd9Sstevel@tonic-gate 		priv = "system";
547c478bd9Sstevel@tonic-gate 		break;
557c478bd9Sstevel@tonic-gate 	default:
567c478bd9Sstevel@tonic-gate 		priv = "???";
577c478bd9Sstevel@tonic-gate 		break;
587c478bd9Sstevel@tonic-gate 	};
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	mdb_printf("\t%s ", addr == *enforced ? "(cur)": "     ");
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	mdb_printf("%-#18llx %11s\tflags=<%b>\n",
637c478bd9Sstevel@tonic-gate 	    val->rcv_value, priv, val->rcv_flagaction, val_localflag_bits);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate int
rctl(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)697c478bd9Sstevel@tonic-gate rctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	rctl_t rctl;
727c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t dict;
737c478bd9Sstevel@tonic-gate 	char name[256];
747c478bd9Sstevel@tonic-gate 	rctl_hndl_t hndl;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
777c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rctl, sizeof (rctl_t), addr) == -1) {
807c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_t structure at %p", addr);
817c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
827c478bd9Sstevel@tonic-gate 	}
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	if (argc != 0) {
857c478bd9Sstevel@tonic-gate 		const mdb_arg_t *argp = &argv[0];
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
887c478bd9Sstevel@tonic-gate 			hndl = (rctl_hndl_t)argp->a_un.a_val;
897c478bd9Sstevel@tonic-gate 		else
907c478bd9Sstevel@tonic-gate 			hndl = (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 		if (rctl.rc_id != hndl)
937c478bd9Sstevel@tonic-gate 			return (DCMD_OK);
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dict, sizeof (rctl_dict_entry_t),
977c478bd9Sstevel@tonic-gate 	    (uintptr_t)rctl.rc_dict_entry) == -1) {
987c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dict entry for rctl_t %p at %p",
997c478bd9Sstevel@tonic-gate 		    addr, rctl.rc_dict_entry);
1007c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
1047c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read name for rctl_t %p", addr);
1057c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	mdb_printf("%0?p\t%3d : %s\n", addr, rctl.rc_id, name);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)print_val, &(rctl.rc_cursor),
1117c478bd9Sstevel@tonic-gate 	    addr) == -1) {
1127c478bd9Sstevel@tonic-gate 		mdb_warn("failed to walk all values for rctl_t %p", addr);
1137c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate int
rctl_dict(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1207c478bd9Sstevel@tonic-gate rctl_dict(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t dict;
1237c478bd9Sstevel@tonic-gate 	char name[256], *type = NULL;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
1267c478bd9Sstevel@tonic-gate 		if (mdb_walk_dcmd("rctl_dict_list", "rctl_dict", argc,
1277c478bd9Sstevel@tonic-gate 		    argv) == -1) {
1287c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk 'rctl_dict_list'");
1297c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
1307c478bd9Sstevel@tonic-gate 		}
1317c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
1357c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%2s %-27s %?s %7s %s%</u>\n",
1367c478bd9Sstevel@tonic-gate 		    "ID", "NAME", "ADDR", "TYPE", "GLOBAL_FLAGS");
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dict, sizeof (dict), addr) == -1) {
1397c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_dict at %p", addr);
1407c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
1437c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_dict name for %p", addr);
1447c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	switch (dict.rcd_entity) {
1487c478bd9Sstevel@tonic-gate 	case RCENTITY_PROCESS:
1497c478bd9Sstevel@tonic-gate 		type = "process";
1507c478bd9Sstevel@tonic-gate 		break;
1517c478bd9Sstevel@tonic-gate 	case RCENTITY_TASK:
1527c478bd9Sstevel@tonic-gate 		type = "task";
1537c478bd9Sstevel@tonic-gate 		break;
1547c478bd9Sstevel@tonic-gate 	case RCENTITY_PROJECT:
1557c478bd9Sstevel@tonic-gate 		type = "project";
1567c478bd9Sstevel@tonic-gate 		break;
1577c478bd9Sstevel@tonic-gate 	case RCENTITY_ZONE:
1587c478bd9Sstevel@tonic-gate 		type = "zone";
1597c478bd9Sstevel@tonic-gate 		break;
1607c478bd9Sstevel@tonic-gate 	default:
1617c478bd9Sstevel@tonic-gate 		type = "unknown";
1627c478bd9Sstevel@tonic-gate 		break;
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	mdb_printf("%2d %-27s %0?p %7s 0x%08x", dict.rcd_id, name, addr,
1667c478bd9Sstevel@tonic-gate 	    type, dict.rcd_flagaction);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate typedef struct dict_data {
1727c478bd9Sstevel@tonic-gate 	rctl_hndl_t hndl;
1737c478bd9Sstevel@tonic-gate 	uintptr_t dict_addr;
1747c478bd9Sstevel@tonic-gate 	rctl_entity_t type;
1757c478bd9Sstevel@tonic-gate } dict_data_t;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static int
hndl2dict(uintptr_t addr,rctl_dict_entry_t * entry,dict_data_t * data)1787c478bd9Sstevel@tonic-gate hndl2dict(uintptr_t addr, rctl_dict_entry_t *entry, dict_data_t *data)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	if (data->hndl == entry->rcd_id) {
1817c478bd9Sstevel@tonic-gate 		data->dict_addr = addr;
1827c478bd9Sstevel@tonic-gate 		data->type = entry->rcd_entity;
1837c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * Print out all project, task, and process rctls for a given process.
1917c478bd9Sstevel@tonic-gate  * If a handle is specified, print only the rctl matching that handle
1927c478bd9Sstevel@tonic-gate  * for the process.
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate int
rctl_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1957c478bd9Sstevel@tonic-gate rctl_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	proc_t proc;
1987c478bd9Sstevel@tonic-gate 	uintptr_t set;
1997c478bd9Sstevel@tonic-gate 	task_t task;
2007c478bd9Sstevel@tonic-gate 	kproject_t proj;
2017c478bd9Sstevel@tonic-gate 	zone_t zone;
2027c478bd9Sstevel@tonic-gate 	dict_data_t rdict;
2037c478bd9Sstevel@tonic-gate 	int i;
2047c478bd9Sstevel@tonic-gate 
205*892ad162SToomas Soome 	rdict.dict_addr = 0;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
2087c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (argc == 0)
2117c478bd9Sstevel@tonic-gate 		rdict.hndl = 0;
2127c478bd9Sstevel@tonic-gate 	else if (argc == 1) {
2137c478bd9Sstevel@tonic-gate 		/*
2147c478bd9Sstevel@tonic-gate 		 * User specified a handle. Go find the rctl_dict_entity_t
2157c478bd9Sstevel@tonic-gate 		 * structure so we know what type of rctl to look for.
2167c478bd9Sstevel@tonic-gate 		 */
2177c478bd9Sstevel@tonic-gate 		const mdb_arg_t *argp = &argv[0];
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
2207c478bd9Sstevel@tonic-gate 			rdict.hndl = (rctl_hndl_t)argp->a_un.a_val;
2217c478bd9Sstevel@tonic-gate 		else
2227c478bd9Sstevel@tonic-gate 			rdict.hndl =
2237c478bd9Sstevel@tonic-gate 			    (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		if (mdb_walk("rctl_dict_list", (mdb_walk_cb_t)hndl2dict,
2267c478bd9Sstevel@tonic-gate 		    &rdict) == -1) {
2277c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk rctl_dict_list");
2287c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
2297c478bd9Sstevel@tonic-gate 		}
2307c478bd9Sstevel@tonic-gate 		/* Couldn't find a rctl_dict_entry_t for this handle */
231*892ad162SToomas Soome 		if (rdict.dict_addr == 0)
2327c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
2337c478bd9Sstevel@tonic-gate 	} else
2347c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if (mdb_vread(&proc, sizeof (proc_t), addr) == -1) {
2387c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read proc at %p", addr);
2397c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 	if (mdb_vread(&zone, sizeof (zone_t), (uintptr_t)proc.p_zone) == -1) {
2427c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read zone at %p", proc.p_zone);
2437c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 	if (mdb_vread(&task, sizeof (task_t), (uintptr_t)proc.p_task) == -1) {
2467c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read task at %p", proc.p_task);
2477c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	if (mdb_vread(&proj, sizeof (kproject_t),
2507c478bd9Sstevel@tonic-gate 	    (uintptr_t)task.tk_proj) == -1) {
2517c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read proj at %p", task.tk_proj);
2527c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	for (i = 0; i <= RC_MAX_ENTITY; i++) {
2567c478bd9Sstevel@tonic-gate 		/*
2577c478bd9Sstevel@tonic-gate 		 * If user didn't specify a handle, print rctls for all
2587c478bd9Sstevel@tonic-gate 		 * types. Otherwise, we can walk the rctl_set for only the
2597c478bd9Sstevel@tonic-gate 		 * entity specified by the handle.
2607c478bd9Sstevel@tonic-gate 		 */
2617c478bd9Sstevel@tonic-gate 		if (rdict.hndl != 0 && rdict.type != i)
2627c478bd9Sstevel@tonic-gate 			continue;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		switch (i) {
2657c478bd9Sstevel@tonic-gate 		case (RCENTITY_PROCESS):
2667c478bd9Sstevel@tonic-gate 			set = (uintptr_t)proc.p_rctls;
2677c478bd9Sstevel@tonic-gate 			break;
2687c478bd9Sstevel@tonic-gate 		case (RCENTITY_TASK):
2697c478bd9Sstevel@tonic-gate 			set = (uintptr_t)task.tk_rctls;
2707c478bd9Sstevel@tonic-gate 			break;
2717c478bd9Sstevel@tonic-gate 		case (RCENTITY_PROJECT):
2727c478bd9Sstevel@tonic-gate 			set = (uintptr_t)proj.kpj_rctls;
2737c478bd9Sstevel@tonic-gate 			break;
2747c478bd9Sstevel@tonic-gate 		case (RCENTITY_ZONE):
2757c478bd9Sstevel@tonic-gate 			set = (uintptr_t)zone.zone_rctls;
2767c478bd9Sstevel@tonic-gate 			break;
2777c478bd9Sstevel@tonic-gate 		default:
2787c478bd9Sstevel@tonic-gate 			mdb_warn("Unknown rctl type %d", i);
2797c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("rctl_set", "rctl", argc, argv, set) == -1) {
2837c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk rctls in set %p", set);
2847c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate typedef struct dict_walk_data {
2927c478bd9Sstevel@tonic-gate 	int num_dicts;
2937c478bd9Sstevel@tonic-gate 	int num_cur;
2947c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t **curdict;
2957c478bd9Sstevel@tonic-gate } dict_walk_data_t;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate int
rctl_dict_walk_init(mdb_walk_state_t * wsp)2987c478bd9Sstevel@tonic-gate rctl_dict_walk_init(mdb_walk_state_t *wsp)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 	uintptr_t ptr;
3017c478bd9Sstevel@tonic-gate 	int nlists;
3027c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
3037c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t **dicts;
3047c478bd9Sstevel@tonic-gate 	dict_walk_data_t *dwd;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (mdb_lookup_by_name("rctl_lists", &sym) == -1) {
3077c478bd9Sstevel@tonic-gate 		mdb_warn("failed to find 'rctl_lists'\n");
3087c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	nlists = sym.st_size / sizeof (rctl_dict_entry_t *);
3127c478bd9Sstevel@tonic-gate 	ptr = (uintptr_t)sym.st_value;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	dicts = mdb_alloc(nlists * sizeof (rctl_dict_entry_t *), UM_SLEEP);
3157c478bd9Sstevel@tonic-gate 	mdb_vread(dicts, sym.st_size, ptr);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	dwd = mdb_alloc(sizeof (dict_walk_data_t), UM_SLEEP);
3187c478bd9Sstevel@tonic-gate 	dwd->num_dicts = nlists;
3197c478bd9Sstevel@tonic-gate 	dwd->num_cur = 0;
3207c478bd9Sstevel@tonic-gate 	dwd->curdict = dicts;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	wsp->walk_addr = 0;
3237c478bd9Sstevel@tonic-gate 	wsp->walk_data = dwd;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate int
rctl_dict_walk_step(mdb_walk_state_t * wsp)3297c478bd9Sstevel@tonic-gate rctl_dict_walk_step(mdb_walk_state_t *wsp)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	dict_walk_data_t *dwd = wsp->walk_data;
3327c478bd9Sstevel@tonic-gate 	uintptr_t dp;
3337c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t entry;
3347c478bd9Sstevel@tonic-gate 	int status;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	dp = (uintptr_t)((dwd->curdict)[dwd->num_cur]);
3377c478bd9Sstevel@tonic-gate 
338*892ad162SToomas Soome 	while (dp != 0) {
3397c478bd9Sstevel@tonic-gate 		if (mdb_vread(&entry, sizeof (rctl_dict_entry_t), dp) == -1) {
3407c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read rctl_dict_entry_t structure "
3417c478bd9Sstevel@tonic-gate 			    "at %p", dp);
3427c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		status = wsp->walk_callback(dp, &entry, wsp->walk_cbdata);
3467c478bd9Sstevel@tonic-gate 		if (status != WALK_NEXT)
3477c478bd9Sstevel@tonic-gate 			return (status);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		dp = (uintptr_t)entry.rcd_next;
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	dwd->num_cur++;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (dwd->num_cur == dwd->num_dicts)
3557c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate void
rctl_dict_walk_fini(mdb_walk_state_t * wsp)3617c478bd9Sstevel@tonic-gate rctl_dict_walk_fini(mdb_walk_state_t *wsp)
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate 	dict_walk_data_t *wd = wsp->walk_data;
3647c478bd9Sstevel@tonic-gate 	mdb_free(wd->curdict, wd->num_dicts * sizeof (rctl_dict_entry_t *));
3657c478bd9Sstevel@tonic-gate 	mdb_free(wd, sizeof (dict_walk_data_t));
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate typedef struct set_walk_data {
3697c478bd9Sstevel@tonic-gate 	uint_t hashsize;
3707c478bd9Sstevel@tonic-gate 	int hashcur;
3717c478bd9Sstevel@tonic-gate 	void **hashloc;
3727c478bd9Sstevel@tonic-gate } set_walk_data_t;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate int
rctl_set_walk_init(mdb_walk_state_t * wsp)3757c478bd9Sstevel@tonic-gate rctl_set_walk_init(mdb_walk_state_t *wsp)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	rctl_set_t rset;
3787c478bd9Sstevel@tonic-gate 	uint_t hashsz;
3797c478bd9Sstevel@tonic-gate 	set_walk_data_t *swd;
3807c478bd9Sstevel@tonic-gate 	rctl_t **rctls;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rset, sizeof (rctl_set_t), wsp->walk_addr) == -1) {
3837c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rset at %p", wsp->walk_addr);
3847c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&hashsz, "rctl_set_size") == -1 || hashsz == 0) {
3887c478bd9Sstevel@tonic-gate 		mdb_warn("rctl_set_size not found or invalid");
3897c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	rctls = mdb_alloc(hashsz * sizeof (rctl_t *), UM_SLEEP);
3937c478bd9Sstevel@tonic-gate 	if (mdb_vread(rctls, hashsz * sizeof (rctl_t *),
3947c478bd9Sstevel@tonic-gate 	    (uintptr_t)rset.rcs_ctls) == -1) {
3957c478bd9Sstevel@tonic-gate 		mdb_warn("cannot read rctl hash at %p", rset.rcs_ctls);
3967c478bd9Sstevel@tonic-gate 		mdb_free(rctls, hashsz * sizeof (rctl_t *));
3977c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	swd = mdb_alloc(sizeof (set_walk_data_t), UM_SLEEP);
4017c478bd9Sstevel@tonic-gate 	swd->hashsize = hashsz;
4027c478bd9Sstevel@tonic-gate 	swd->hashcur = 0;
4037c478bd9Sstevel@tonic-gate 	swd->hashloc = (void **)rctls;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	wsp->walk_addr = 0;
4067c478bd9Sstevel@tonic-gate 	wsp->walk_data = swd;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate int
rctl_set_walk_step(mdb_walk_state_t * wsp)4137c478bd9Sstevel@tonic-gate rctl_set_walk_step(mdb_walk_state_t *wsp)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	set_walk_data_t	*swd = wsp->walk_data;
4167c478bd9Sstevel@tonic-gate 	rctl_t rctl;
4177c478bd9Sstevel@tonic-gate 	void **rhash = swd->hashloc;
4187c478bd9Sstevel@tonic-gate 	int status;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (swd->hashcur >= swd->hashsize)
4217c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4227c478bd9Sstevel@tonic-gate 
423*892ad162SToomas Soome 	if (wsp->walk_addr == 0) {
4247c478bd9Sstevel@tonic-gate 		while (swd->hashcur < swd->hashsize) {
4257c478bd9Sstevel@tonic-gate 			if (rhash[swd->hashcur] != NULL) {
4267c478bd9Sstevel@tonic-gate 				break;
4277c478bd9Sstevel@tonic-gate 			}
4287c478bd9Sstevel@tonic-gate 			swd->hashcur++;
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 		if (rhash[swd->hashcur] == NULL ||
4327c478bd9Sstevel@tonic-gate 		    swd->hashcur >= swd->hashsize)
4337c478bd9Sstevel@tonic-gate 			return (WALK_DONE);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)rhash[swd->hashcur];
4367c478bd9Sstevel@tonic-gate 		swd->hashcur++;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
440*892ad162SToomas Soome 		wsp->walk_addr = 0;
4417c478bd9Sstevel@tonic-gate 		mdb_warn("unable to read from %#p", wsp->walk_addr);
4427c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &rctl, wsp->walk_cbdata);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)rctl.rc_next;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	return (status);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate void
rctl_set_walk_fini(mdb_walk_state_t * wsp)4537c478bd9Sstevel@tonic-gate rctl_set_walk_fini(mdb_walk_state_t *wsp)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	set_walk_data_t *sd = wsp->walk_data;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	mdb_free(sd->hashloc, sd->hashsize * sizeof (rctl_t *));
4587c478bd9Sstevel@tonic-gate 	mdb_free(sd, sizeof (set_walk_data_t));
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate int
rctl_val_walk_init(mdb_walk_state_t * wsp)4627c478bd9Sstevel@tonic-gate rctl_val_walk_init(mdb_walk_state_t *wsp)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	rctl_t rctl;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
4677c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl at %p", wsp->walk_addr);
4687c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)rctl.rc_values;
4717c478bd9Sstevel@tonic-gate 	wsp->walk_data = rctl.rc_values;
4727c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate int
rctl_val_walk_step(mdb_walk_state_t * wsp)4767c478bd9Sstevel@tonic-gate rctl_val_walk_step(mdb_walk_state_t *wsp)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	rctl_val_t val;
4797c478bd9Sstevel@tonic-gate 	int status;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (mdb_vread(&val, sizeof (rctl_val_t), wsp->walk_addr) == -1) {
4827c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_val at %p", wsp->walk_addr);
4837c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &val, wsp->walk_cbdata);
4877c478bd9Sstevel@tonic-gate 
488*892ad162SToomas Soome 	if ((wsp->walk_addr = (uintptr_t)val.rcv_next) == 0)
4897c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	return (status);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate typedef struct rctl_val_seen {
4957c478bd9Sstevel@tonic-gate 	uintptr_t		s_ptr;
4967c478bd9Sstevel@tonic-gate 	rctl_qty_t		s_val;
4977c478bd9Sstevel@tonic-gate } rctl_val_seen_t;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate typedef struct rctl_validate_data {
5007c478bd9Sstevel@tonic-gate 	uintptr_t		v_rctl_addr;
5017c478bd9Sstevel@tonic-gate 	rctl_val_t		*v_cursor;
5027c478bd9Sstevel@tonic-gate 	uint_t			v_flags;
5037c478bd9Sstevel@tonic-gate 	int			v_bad_rctl;
5047c478bd9Sstevel@tonic-gate 	int			v_cursor_valid;
5057c478bd9Sstevel@tonic-gate 	int			v_circularity_detected;
5067c478bd9Sstevel@tonic-gate 	uint_t			v_seen_size;
5077c478bd9Sstevel@tonic-gate 	uint_t			v_seen_cnt;
5087c478bd9Sstevel@tonic-gate 	rctl_val_seen_t		*v_seen;
5097c478bd9Sstevel@tonic-gate } rctl_validate_data_t;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate #define	RCV_VERBOSE 0x1
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate  * rctl_val_validate()
5157c478bd9Sstevel@tonic-gate  * Do validation on an individual rctl_val_t. This function is called
5167c478bd9Sstevel@tonic-gate  * as part of the rctl_val walker, and helps perform the checks described
5177c478bd9Sstevel@tonic-gate  * in the ::rctl_validate dcmd.
5187c478bd9Sstevel@tonic-gate  */
5197c478bd9Sstevel@tonic-gate static int
rctl_val_validate(uintptr_t addr,rctl_val_t * val,rctl_validate_data_t * data)5207c478bd9Sstevel@tonic-gate rctl_val_validate(uintptr_t addr, rctl_val_t *val, rctl_validate_data_t *data)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate 	int i;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	data->v_seen[data->v_seen_cnt].s_ptr = addr;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if (addr == (uintptr_t)data->v_cursor)
5277c478bd9Sstevel@tonic-gate 		data->v_cursor_valid++;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	data->v_seen[data->v_seen_cnt].s_val = val->rcv_value;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (val->rcv_prev == (void *)0xbaddcafe ||
5327c478bd9Sstevel@tonic-gate 	    val->rcv_next == (void *)0xbaddcafe ||
5337c478bd9Sstevel@tonic-gate 	    val->rcv_prev == (void *)0xdeadbeef ||
5347c478bd9Sstevel@tonic-gate 	    val->rcv_next == (void *)0xdeadbeef) {
5357c478bd9Sstevel@tonic-gate 		if (data->v_bad_rctl++ == 0)
5367c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", data->v_rctl_addr);
5377c478bd9Sstevel@tonic-gate 		if (data->v_flags & RCV_VERBOSE)
5387c478bd9Sstevel@tonic-gate 			mdb_printf("/ uninitialized or previously "
5397c478bd9Sstevel@tonic-gate 			    "freed link at %p ", addr);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (data->v_seen_cnt == 0) {
5437c478bd9Sstevel@tonic-gate 		if (val->rcv_prev != NULL) {
5447c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
5457c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
5467c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
5477c478bd9Sstevel@tonic-gate 				mdb_printf("/ bad prev pointer at "
5487c478bd9Sstevel@tonic-gate 				    "head ");
5497c478bd9Sstevel@tonic-gate 		}
5507c478bd9Sstevel@tonic-gate 	} else {
5517c478bd9Sstevel@tonic-gate 		if ((uintptr_t)val->rcv_prev !=
5527c478bd9Sstevel@tonic-gate 		    data->v_seen[data->v_seen_cnt - 1].s_ptr) {
5537c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
5547c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
5557c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
5567c478bd9Sstevel@tonic-gate 				mdb_printf("/ bad prev pointer at %p ",
5577c478bd9Sstevel@tonic-gate 				    addr);
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		if (data->v_seen[data->v_seen_cnt].s_val <
5617c478bd9Sstevel@tonic-gate 		    data->v_seen[data->v_seen_cnt - 1].s_val) {
5627c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
5637c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
5647c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
5657c478bd9Sstevel@tonic-gate 				mdb_printf("/ ordering error at %p ",
5667c478bd9Sstevel@tonic-gate 				    addr);
5677c478bd9Sstevel@tonic-gate 		}
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	for (i = data->v_seen_cnt; i >= 0; i--) {
5717c478bd9Sstevel@tonic-gate 		if (data->v_seen[i].s_ptr == (uintptr_t)val->rcv_next) {
5727c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
5737c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
5747c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
5757c478bd9Sstevel@tonic-gate 				mdb_printf("/ circular next pointer "
5767c478bd9Sstevel@tonic-gate 				    "at %p ", addr);
5777c478bd9Sstevel@tonic-gate 			data->v_circularity_detected++;
5787c478bd9Sstevel@tonic-gate 			break;
5797c478bd9Sstevel@tonic-gate 		}
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if (data->v_circularity_detected)
5837c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	data->v_seen_cnt++;
5867c478bd9Sstevel@tonic-gate 	if (data->v_seen_cnt >= data->v_seen_size) {
5877c478bd9Sstevel@tonic-gate 		uint_t new_seen_size = data->v_seen_size * 2;
5887c478bd9Sstevel@tonic-gate 		rctl_val_seen_t *tseen = mdb_zalloc(new_seen_size *
5897c478bd9Sstevel@tonic-gate 		    sizeof (rctl_val_seen_t), UM_SLEEP | UM_GC);
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 		bcopy(data->v_seen, tseen, data->v_seen_size *
5927c478bd9Sstevel@tonic-gate 		    sizeof (rctl_val_seen_t));
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 		data->v_seen = tseen;
5957c478bd9Sstevel@tonic-gate 		data->v_seen_size = new_seen_size;
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate  * Validate a rctl pointer by checking:
6037c478bd9Sstevel@tonic-gate  *   - rctl_val_t's for that rctl form an ordered, non-circular list
6047c478bd9Sstevel@tonic-gate  *   - the cursor points to a rctl_val_t within that list
6057c478bd9Sstevel@tonic-gate  *   - there are no more than UINT64_MAX (or # specified by -n)
6067c478bd9Sstevel@tonic-gate  *     rctl_val_t's in the list
6077c478bd9Sstevel@tonic-gate  */
6087c478bd9Sstevel@tonic-gate int
rctl_validate(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6097c478bd9Sstevel@tonic-gate rctl_validate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate 	rctl_validate_data_t data;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	rctl_t r;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	uint64_t long_threshold = UINT64_MAX;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	/* Initialize validate data structure */
6187c478bd9Sstevel@tonic-gate 	data.v_rctl_addr = addr;
6197c478bd9Sstevel@tonic-gate 	data.v_flags = 0;
6207c478bd9Sstevel@tonic-gate 	data.v_bad_rctl = 0;
6217c478bd9Sstevel@tonic-gate 	data.v_seen_cnt = 0;
6227c478bd9Sstevel@tonic-gate 	data.v_cursor_valid = 0;
6237c478bd9Sstevel@tonic-gate 	data.v_circularity_detected = 0;
6247c478bd9Sstevel@tonic-gate 	data.v_seen_size = 1;
6257c478bd9Sstevel@tonic-gate 	data.v_seen = mdb_zalloc(data.v_seen_size * sizeof (rctl_val_seen_t),
6267c478bd9Sstevel@tonic-gate 	    UM_SLEEP | UM_GC);
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
6297c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
6327c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, RCV_VERBOSE, &data.v_flags,
6337c478bd9Sstevel@tonic-gate 	    'n', MDB_OPT_UINT64, &long_threshold,
6347c478bd9Sstevel@tonic-gate 	    NULL) != argc)
6357c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if (mdb_vread(&r, sizeof (rctl_t), addr) != sizeof (rctl_t)) {
6387c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl structure at %p", addr);
6397c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	data.v_cursor = r.rc_cursor;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	if (data.v_cursor == NULL) {
6457c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
6467c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
6477c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
6487c478bd9Sstevel@tonic-gate 			mdb_printf("/ NULL cursor seen ");
6497c478bd9Sstevel@tonic-gate 	} else if (data.v_cursor == (rctl_val_t *)0xbaddcafe) {
6507c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
6517c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
6527c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
6537c478bd9Sstevel@tonic-gate 			mdb_printf("/ uninitialized cursor seen ");
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	/* Walk through each val in this rctl for individual validation. */
6577c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)rctl_val_validate, &data,
6587c478bd9Sstevel@tonic-gate 	    addr) == -1) {
6597c478bd9Sstevel@tonic-gate 		mdb_warn("failed to walk all values for rctl_t %p", addr);
6607c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (data.v_seen_cnt >= long_threshold) {
6647c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
6657c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
6667c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
6677c478bd9Sstevel@tonic-gate 			mdb_printf("/ sequence length = %d ",
6687c478bd9Sstevel@tonic-gate 			    data.v_seen_cnt);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	if (!data.v_cursor_valid) {
6727c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
6737c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
6747c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
6757c478bd9Sstevel@tonic-gate 			mdb_printf("/ cursor outside sequence");
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	if (data.v_bad_rctl)
6797c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	if (data.v_circularity_detected)
6827c478bd9Sstevel@tonic-gate 		mdb_warn("circular list implies possible memory leak; "
6837c478bd9Sstevel@tonic-gate 		    "recommend invoking ::findleaks");
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
6867c478bd9Sstevel@tonic-gate }
687