xref: /titanic_52/usr/src/cmd/mdb/common/modules/genunix/rctl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/task.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/project.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/zone.h>
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate static int
37*7c478bd9Sstevel@tonic-gate print_val(uintptr_t addr, rctl_val_t *val, uintptr_t *enforced)
38*7c478bd9Sstevel@tonic-gate {
39*7c478bd9Sstevel@tonic-gate 	char *priv;
40*7c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t val_localflag_bits[] = {
41*7c478bd9Sstevel@tonic-gate 		{ "SIGNAL", RCTL_LOCAL_SIGNAL, RCTL_LOCAL_SIGNAL },
42*7c478bd9Sstevel@tonic-gate 		{ "DENY", RCTL_LOCAL_DENY, RCTL_LOCAL_DENY },
43*7c478bd9Sstevel@tonic-gate 		{ "MAX", RCTL_LOCAL_MAXIMAL, RCTL_LOCAL_MAXIMAL },
44*7c478bd9Sstevel@tonic-gate 		{ NULL, 0, 0 }
45*7c478bd9Sstevel@tonic-gate 	};
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate 	switch (val->rcv_privilege) {
48*7c478bd9Sstevel@tonic-gate 	case (RCPRIV_BASIC):
49*7c478bd9Sstevel@tonic-gate 		priv = "basic";
50*7c478bd9Sstevel@tonic-gate 		break;
51*7c478bd9Sstevel@tonic-gate 	case (RCPRIV_PRIVILEGED):
52*7c478bd9Sstevel@tonic-gate 		priv = "privileged";
53*7c478bd9Sstevel@tonic-gate 		break;
54*7c478bd9Sstevel@tonic-gate 	case (RCPRIV_SYSTEM):
55*7c478bd9Sstevel@tonic-gate 		priv = "system";
56*7c478bd9Sstevel@tonic-gate 		break;
57*7c478bd9Sstevel@tonic-gate 	default:
58*7c478bd9Sstevel@tonic-gate 		priv = "???";
59*7c478bd9Sstevel@tonic-gate 		break;
60*7c478bd9Sstevel@tonic-gate 	};
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	mdb_printf("\t%s ", addr == *enforced ? "(cur)": "     ");
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	mdb_printf("%-#18llx %11s\tflags=<%b>\n",
65*7c478bd9Sstevel@tonic-gate 	    val->rcv_value, priv, val->rcv_flagaction, val_localflag_bits);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
68*7c478bd9Sstevel@tonic-gate }
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate int
71*7c478bd9Sstevel@tonic-gate rctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
72*7c478bd9Sstevel@tonic-gate {
73*7c478bd9Sstevel@tonic-gate 	rctl_t rctl;
74*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t dict;
75*7c478bd9Sstevel@tonic-gate 	char name[256];
76*7c478bd9Sstevel@tonic-gate 	rctl_hndl_t hndl;
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
79*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rctl, sizeof (rctl_t), addr) == -1) {
82*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_t structure at %p", addr);
83*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
84*7c478bd9Sstevel@tonic-gate 	}
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	if (argc != 0) {
87*7c478bd9Sstevel@tonic-gate 		const mdb_arg_t *argp = &argv[0];
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
90*7c478bd9Sstevel@tonic-gate 			hndl = (rctl_hndl_t)argp->a_un.a_val;
91*7c478bd9Sstevel@tonic-gate 		else
92*7c478bd9Sstevel@tonic-gate 			hndl = (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 		if (rctl.rc_id != hndl)
95*7c478bd9Sstevel@tonic-gate 			return (DCMD_OK);
96*7c478bd9Sstevel@tonic-gate 	}
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dict, sizeof (rctl_dict_entry_t),
99*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)rctl.rc_dict_entry) == -1) {
100*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dict entry for rctl_t %p at %p",
101*7c478bd9Sstevel@tonic-gate 		    addr, rctl.rc_dict_entry);
102*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
103*7c478bd9Sstevel@tonic-gate 	}
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
106*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read name for rctl_t %p", addr);
107*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
108*7c478bd9Sstevel@tonic-gate 	}
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	mdb_printf("%0?p\t%3d : %s\n", addr, rctl.rc_id, name);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)print_val, &(rctl.rc_cursor),
113*7c478bd9Sstevel@tonic-gate 	    addr) == -1) {
114*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to walk all values for rctl_t %p", addr);
115*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
116*7c478bd9Sstevel@tonic-gate 	}
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
119*7c478bd9Sstevel@tonic-gate }
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate int
122*7c478bd9Sstevel@tonic-gate rctl_dict(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t dict;
125*7c478bd9Sstevel@tonic-gate 	char name[256], *type = NULL;
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
128*7c478bd9Sstevel@tonic-gate 		if (mdb_walk_dcmd("rctl_dict_list", "rctl_dict", argc,
129*7c478bd9Sstevel@tonic-gate 		    argv) == -1) {
130*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk 'rctl_dict_list'");
131*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
132*7c478bd9Sstevel@tonic-gate 		}
133*7c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
134*7c478bd9Sstevel@tonic-gate 	}
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
137*7c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%2s %-27s %?s %7s %s%</u>\n",
138*7c478bd9Sstevel@tonic-gate 		    "ID", "NAME", "ADDR", "TYPE", "GLOBAL_FLAGS");
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dict, sizeof (dict), addr) == -1) {
141*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_dict at %p", addr);
142*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
143*7c478bd9Sstevel@tonic-gate 	}
144*7c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, 256, (uintptr_t)(dict.rcd_name)) == -1) {
145*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_dict name for %p", addr);
146*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
147*7c478bd9Sstevel@tonic-gate 	}
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	switch (dict.rcd_entity) {
150*7c478bd9Sstevel@tonic-gate 	case RCENTITY_PROCESS:
151*7c478bd9Sstevel@tonic-gate 		type = "process";
152*7c478bd9Sstevel@tonic-gate 		break;
153*7c478bd9Sstevel@tonic-gate 	case RCENTITY_TASK:
154*7c478bd9Sstevel@tonic-gate 		type = "task";
155*7c478bd9Sstevel@tonic-gate 		break;
156*7c478bd9Sstevel@tonic-gate 	case RCENTITY_PROJECT:
157*7c478bd9Sstevel@tonic-gate 		type = "project";
158*7c478bd9Sstevel@tonic-gate 		break;
159*7c478bd9Sstevel@tonic-gate 	case RCENTITY_ZONE:
160*7c478bd9Sstevel@tonic-gate 		type = "zone";
161*7c478bd9Sstevel@tonic-gate 		break;
162*7c478bd9Sstevel@tonic-gate 	default:
163*7c478bd9Sstevel@tonic-gate 		type = "unknown";
164*7c478bd9Sstevel@tonic-gate 		break;
165*7c478bd9Sstevel@tonic-gate 	}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	mdb_printf("%2d %-27s %0?p %7s 0x%08x", dict.rcd_id, name, addr,
168*7c478bd9Sstevel@tonic-gate 	    type, dict.rcd_flagaction);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate typedef struct dict_data {
174*7c478bd9Sstevel@tonic-gate 	rctl_hndl_t hndl;
175*7c478bd9Sstevel@tonic-gate 	uintptr_t dict_addr;
176*7c478bd9Sstevel@tonic-gate 	rctl_entity_t type;
177*7c478bd9Sstevel@tonic-gate } dict_data_t;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate static int
180*7c478bd9Sstevel@tonic-gate hndl2dict(uintptr_t addr, rctl_dict_entry_t *entry, dict_data_t *data)
181*7c478bd9Sstevel@tonic-gate {
182*7c478bd9Sstevel@tonic-gate 	if (data->hndl == entry->rcd_id) {
183*7c478bd9Sstevel@tonic-gate 		data->dict_addr = addr;
184*7c478bd9Sstevel@tonic-gate 		data->type = entry->rcd_entity;
185*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
186*7c478bd9Sstevel@tonic-gate 	}
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
189*7c478bd9Sstevel@tonic-gate }
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /*
192*7c478bd9Sstevel@tonic-gate  * Print out all project, task, and process rctls for a given process.
193*7c478bd9Sstevel@tonic-gate  * If a handle is specified, print only the rctl matching that handle
194*7c478bd9Sstevel@tonic-gate  * for the process.
195*7c478bd9Sstevel@tonic-gate  */
196*7c478bd9Sstevel@tonic-gate int
197*7c478bd9Sstevel@tonic-gate rctl_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
198*7c478bd9Sstevel@tonic-gate {
199*7c478bd9Sstevel@tonic-gate 	proc_t proc;
200*7c478bd9Sstevel@tonic-gate 	uintptr_t set;
201*7c478bd9Sstevel@tonic-gate 	task_t task;
202*7c478bd9Sstevel@tonic-gate 	kproject_t proj;
203*7c478bd9Sstevel@tonic-gate 	zone_t zone;
204*7c478bd9Sstevel@tonic-gate 	dict_data_t rdict;
205*7c478bd9Sstevel@tonic-gate 	int i;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	rdict.dict_addr = NULL;
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
210*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	if (argc == 0)
213*7c478bd9Sstevel@tonic-gate 		rdict.hndl = 0;
214*7c478bd9Sstevel@tonic-gate 	else if (argc == 1) {
215*7c478bd9Sstevel@tonic-gate 		/*
216*7c478bd9Sstevel@tonic-gate 		 * User specified a handle. Go find the rctl_dict_entity_t
217*7c478bd9Sstevel@tonic-gate 		 * structure so we know what type of rctl to look for.
218*7c478bd9Sstevel@tonic-gate 		 */
219*7c478bd9Sstevel@tonic-gate 		const mdb_arg_t *argp = &argv[0];
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
222*7c478bd9Sstevel@tonic-gate 			rdict.hndl = (rctl_hndl_t)argp->a_un.a_val;
223*7c478bd9Sstevel@tonic-gate 		else
224*7c478bd9Sstevel@tonic-gate 			rdict.hndl =
225*7c478bd9Sstevel@tonic-gate 			    (rctl_hndl_t)mdb_strtoull(argp->a_un.a_str);
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 		if (mdb_walk("rctl_dict_list", (mdb_walk_cb_t)hndl2dict,
228*7c478bd9Sstevel@tonic-gate 		    &rdict) == -1) {
229*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk rctl_dict_list");
230*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 		/* Couldn't find a rctl_dict_entry_t for this handle */
233*7c478bd9Sstevel@tonic-gate 		if (rdict.dict_addr == NULL)
234*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
235*7c478bd9Sstevel@tonic-gate 	} else
236*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&proc, sizeof (proc_t), addr) == -1) {
240*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read proc at %p", addr);
241*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&zone, sizeof (zone_t), (uintptr_t)proc.p_zone) == -1) {
244*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read zone at %p", proc.p_zone);
245*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
246*7c478bd9Sstevel@tonic-gate 	}
247*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&task, sizeof (task_t), (uintptr_t)proc.p_task) == -1) {
248*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read task at %p", proc.p_task);
249*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&proj, sizeof (kproject_t),
252*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)task.tk_proj) == -1) {
253*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read proj at %p", task.tk_proj);
254*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= RC_MAX_ENTITY; i++) {
258*7c478bd9Sstevel@tonic-gate 		/*
259*7c478bd9Sstevel@tonic-gate 		 * If user didn't specify a handle, print rctls for all
260*7c478bd9Sstevel@tonic-gate 		 * types. Otherwise, we can walk the rctl_set for only the
261*7c478bd9Sstevel@tonic-gate 		 * entity specified by the handle.
262*7c478bd9Sstevel@tonic-gate 		 */
263*7c478bd9Sstevel@tonic-gate 		if (rdict.hndl != 0 && rdict.type != i)
264*7c478bd9Sstevel@tonic-gate 			continue;
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 		switch (i) {
267*7c478bd9Sstevel@tonic-gate 		case (RCENTITY_PROCESS):
268*7c478bd9Sstevel@tonic-gate 			set = (uintptr_t)proc.p_rctls;
269*7c478bd9Sstevel@tonic-gate 			break;
270*7c478bd9Sstevel@tonic-gate 		case (RCENTITY_TASK):
271*7c478bd9Sstevel@tonic-gate 			set = (uintptr_t)task.tk_rctls;
272*7c478bd9Sstevel@tonic-gate 			break;
273*7c478bd9Sstevel@tonic-gate 		case (RCENTITY_PROJECT):
274*7c478bd9Sstevel@tonic-gate 			set = (uintptr_t)proj.kpj_rctls;
275*7c478bd9Sstevel@tonic-gate 			break;
276*7c478bd9Sstevel@tonic-gate 		case (RCENTITY_ZONE):
277*7c478bd9Sstevel@tonic-gate 			set = (uintptr_t)zone.zone_rctls;
278*7c478bd9Sstevel@tonic-gate 			break;
279*7c478bd9Sstevel@tonic-gate 		default:
280*7c478bd9Sstevel@tonic-gate 			mdb_warn("Unknown rctl type %d", i);
281*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
282*7c478bd9Sstevel@tonic-gate 		}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("rctl_set", "rctl", argc, argv, set) == -1) {
285*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk rctls in set %p", set);
286*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
291*7c478bd9Sstevel@tonic-gate }
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate typedef struct dict_walk_data {
294*7c478bd9Sstevel@tonic-gate 	int num_dicts;
295*7c478bd9Sstevel@tonic-gate 	int num_cur;
296*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t **curdict;
297*7c478bd9Sstevel@tonic-gate } dict_walk_data_t;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate int
300*7c478bd9Sstevel@tonic-gate rctl_dict_walk_init(mdb_walk_state_t *wsp)
301*7c478bd9Sstevel@tonic-gate {
302*7c478bd9Sstevel@tonic-gate 	uintptr_t ptr;
303*7c478bd9Sstevel@tonic-gate 	int nlists;
304*7c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
305*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t **dicts;
306*7c478bd9Sstevel@tonic-gate 	dict_walk_data_t *dwd;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	if (mdb_lookup_by_name("rctl_lists", &sym) == -1) {
309*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to find 'rctl_lists'\n");
310*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
311*7c478bd9Sstevel@tonic-gate 	}
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	nlists = sym.st_size / sizeof (rctl_dict_entry_t *);
314*7c478bd9Sstevel@tonic-gate 	ptr = (uintptr_t)sym.st_value;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	dicts = mdb_alloc(nlists * sizeof (rctl_dict_entry_t *), UM_SLEEP);
317*7c478bd9Sstevel@tonic-gate 	mdb_vread(dicts, sym.st_size, ptr);
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	dwd = mdb_alloc(sizeof (dict_walk_data_t), UM_SLEEP);
320*7c478bd9Sstevel@tonic-gate 	dwd->num_dicts = nlists;
321*7c478bd9Sstevel@tonic-gate 	dwd->num_cur = 0;
322*7c478bd9Sstevel@tonic-gate 	dwd->curdict = dicts;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = 0;
325*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = dwd;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
328*7c478bd9Sstevel@tonic-gate }
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate int
331*7c478bd9Sstevel@tonic-gate rctl_dict_walk_step(mdb_walk_state_t *wsp)
332*7c478bd9Sstevel@tonic-gate {
333*7c478bd9Sstevel@tonic-gate 	dict_walk_data_t *dwd = wsp->walk_data;
334*7c478bd9Sstevel@tonic-gate 	uintptr_t dp;
335*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t entry;
336*7c478bd9Sstevel@tonic-gate 	int status;
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	dp = (uintptr_t)((dwd->curdict)[dwd->num_cur]);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
341*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&entry, sizeof (rctl_dict_entry_t), dp) == -1) {
342*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read rctl_dict_entry_t structure "
343*7c478bd9Sstevel@tonic-gate 			    "at %p", dp);
344*7c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
345*7c478bd9Sstevel@tonic-gate 		}
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		status = wsp->walk_callback(dp, &entry, wsp->walk_cbdata);
348*7c478bd9Sstevel@tonic-gate 		if (status != WALK_NEXT)
349*7c478bd9Sstevel@tonic-gate 			return (status);
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 		dp = (uintptr_t)entry.rcd_next;
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	dwd->num_cur++;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	if (dwd->num_cur == dwd->num_dicts)
357*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate void
363*7c478bd9Sstevel@tonic-gate rctl_dict_walk_fini(mdb_walk_state_t *wsp)
364*7c478bd9Sstevel@tonic-gate {
365*7c478bd9Sstevel@tonic-gate 	dict_walk_data_t *wd = wsp->walk_data;
366*7c478bd9Sstevel@tonic-gate 	mdb_free(wd->curdict, wd->num_dicts * sizeof (rctl_dict_entry_t *));
367*7c478bd9Sstevel@tonic-gate 	mdb_free(wd, sizeof (dict_walk_data_t));
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate typedef struct set_walk_data {
371*7c478bd9Sstevel@tonic-gate 	uint_t hashsize;
372*7c478bd9Sstevel@tonic-gate 	int hashcur;
373*7c478bd9Sstevel@tonic-gate 	void **hashloc;
374*7c478bd9Sstevel@tonic-gate } set_walk_data_t;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate int
377*7c478bd9Sstevel@tonic-gate rctl_set_walk_init(mdb_walk_state_t *wsp)
378*7c478bd9Sstevel@tonic-gate {
379*7c478bd9Sstevel@tonic-gate 	rctl_set_t rset;
380*7c478bd9Sstevel@tonic-gate 	uint_t hashsz;
381*7c478bd9Sstevel@tonic-gate 	set_walk_data_t *swd;
382*7c478bd9Sstevel@tonic-gate 	rctl_t **rctls;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rset, sizeof (rctl_set_t), wsp->walk_addr) == -1) {
385*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rset at %p", wsp->walk_addr);
386*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&hashsz, "rctl_set_size") == -1 || hashsz == 0) {
390*7c478bd9Sstevel@tonic-gate 		mdb_warn("rctl_set_size not found or invalid");
391*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	rctls = mdb_alloc(hashsz * sizeof (rctl_t *), UM_SLEEP);
395*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(rctls, hashsz * sizeof (rctl_t *),
396*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)rset.rcs_ctls) == -1) {
397*7c478bd9Sstevel@tonic-gate 		mdb_warn("cannot read rctl hash at %p", rset.rcs_ctls);
398*7c478bd9Sstevel@tonic-gate 		mdb_free(rctls, hashsz * sizeof (rctl_t *));
399*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	swd = mdb_alloc(sizeof (set_walk_data_t), UM_SLEEP);
403*7c478bd9Sstevel@tonic-gate 	swd->hashsize = hashsz;
404*7c478bd9Sstevel@tonic-gate 	swd->hashcur = 0;
405*7c478bd9Sstevel@tonic-gate 	swd->hashloc = (void **)rctls;
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = 0;
408*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = swd;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
411*7c478bd9Sstevel@tonic-gate }
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate int
415*7c478bd9Sstevel@tonic-gate rctl_set_walk_step(mdb_walk_state_t *wsp)
416*7c478bd9Sstevel@tonic-gate {
417*7c478bd9Sstevel@tonic-gate 	set_walk_data_t	*swd = wsp->walk_data;
418*7c478bd9Sstevel@tonic-gate 	rctl_t rctl;
419*7c478bd9Sstevel@tonic-gate 	void **rhash = swd->hashloc;
420*7c478bd9Sstevel@tonic-gate 	int status;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	if (swd->hashcur >= swd->hashsize)
423*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
426*7c478bd9Sstevel@tonic-gate 		while (swd->hashcur < swd->hashsize) {
427*7c478bd9Sstevel@tonic-gate 			if (rhash[swd->hashcur] != NULL) {
428*7c478bd9Sstevel@tonic-gate 				break;
429*7c478bd9Sstevel@tonic-gate 			}
430*7c478bd9Sstevel@tonic-gate 			swd->hashcur++;
431*7c478bd9Sstevel@tonic-gate 		}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 		if (rhash[swd->hashcur] == NULL ||
434*7c478bd9Sstevel@tonic-gate 		    swd->hashcur >= swd->hashsize)
435*7c478bd9Sstevel@tonic-gate 			return (WALK_DONE);
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)rhash[swd->hashcur];
438*7c478bd9Sstevel@tonic-gate 		swd->hashcur++;
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
442*7c478bd9Sstevel@tonic-gate 		wsp->walk_addr = NULL;
443*7c478bd9Sstevel@tonic-gate 		mdb_warn("unable to read from %#p", wsp->walk_addr);
444*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &rctl, wsp->walk_cbdata);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)rctl.rc_next;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	return (status);
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate void
455*7c478bd9Sstevel@tonic-gate rctl_set_walk_fini(mdb_walk_state_t *wsp)
456*7c478bd9Sstevel@tonic-gate {
457*7c478bd9Sstevel@tonic-gate 	set_walk_data_t *sd = wsp->walk_data;
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	mdb_free(sd->hashloc, sd->hashsize * sizeof (rctl_t *));
460*7c478bd9Sstevel@tonic-gate 	mdb_free(sd, sizeof (set_walk_data_t));
461*7c478bd9Sstevel@tonic-gate }
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate int
464*7c478bd9Sstevel@tonic-gate rctl_val_walk_init(mdb_walk_state_t *wsp)
465*7c478bd9Sstevel@tonic-gate {
466*7c478bd9Sstevel@tonic-gate 	rctl_t rctl;
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rctl, sizeof (rctl_t), wsp->walk_addr) == -1) {
469*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl at %p", wsp->walk_addr);
470*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)rctl.rc_values;
473*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = rctl.rc_values;
474*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
475*7c478bd9Sstevel@tonic-gate }
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate int
478*7c478bd9Sstevel@tonic-gate rctl_val_walk_step(mdb_walk_state_t *wsp)
479*7c478bd9Sstevel@tonic-gate {
480*7c478bd9Sstevel@tonic-gate 	rctl_val_t val;
481*7c478bd9Sstevel@tonic-gate 	int status;
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&val, sizeof (rctl_val_t), wsp->walk_addr) == -1) {
484*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl_val at %p", wsp->walk_addr);
485*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &val, wsp->walk_cbdata);
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if ((wsp->walk_addr = (uintptr_t)val.rcv_next) == NULL)
491*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	return (status);
494*7c478bd9Sstevel@tonic-gate }
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate typedef struct rctl_val_seen {
497*7c478bd9Sstevel@tonic-gate 	uintptr_t		s_ptr;
498*7c478bd9Sstevel@tonic-gate 	rctl_qty_t		s_val;
499*7c478bd9Sstevel@tonic-gate } rctl_val_seen_t;
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate typedef struct rctl_validate_data {
502*7c478bd9Sstevel@tonic-gate 	uintptr_t		v_rctl_addr;
503*7c478bd9Sstevel@tonic-gate 	rctl_val_t		*v_cursor;
504*7c478bd9Sstevel@tonic-gate 	uint_t			v_flags;
505*7c478bd9Sstevel@tonic-gate 	int			v_bad_rctl;
506*7c478bd9Sstevel@tonic-gate 	int			v_cursor_valid;
507*7c478bd9Sstevel@tonic-gate 	int			v_circularity_detected;
508*7c478bd9Sstevel@tonic-gate 	uint_t			v_seen_size;
509*7c478bd9Sstevel@tonic-gate 	uint_t			v_seen_cnt;
510*7c478bd9Sstevel@tonic-gate 	rctl_val_seen_t		*v_seen;
511*7c478bd9Sstevel@tonic-gate } rctl_validate_data_t;
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate #define	RCV_VERBOSE 0x1
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate /*
516*7c478bd9Sstevel@tonic-gate  * rctl_val_validate()
517*7c478bd9Sstevel@tonic-gate  * Do validation on an individual rctl_val_t. This function is called
518*7c478bd9Sstevel@tonic-gate  * as part of the rctl_val walker, and helps perform the checks described
519*7c478bd9Sstevel@tonic-gate  * in the ::rctl_validate dcmd.
520*7c478bd9Sstevel@tonic-gate  */
521*7c478bd9Sstevel@tonic-gate static int
522*7c478bd9Sstevel@tonic-gate rctl_val_validate(uintptr_t addr, rctl_val_t *val, rctl_validate_data_t *data)
523*7c478bd9Sstevel@tonic-gate {
524*7c478bd9Sstevel@tonic-gate 	int i;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	data->v_seen[data->v_seen_cnt].s_ptr = addr;
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	if (addr == (uintptr_t)data->v_cursor)
529*7c478bd9Sstevel@tonic-gate 		data->v_cursor_valid++;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	data->v_seen[data->v_seen_cnt].s_val = val->rcv_value;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	if (val->rcv_prev == (void *)0xbaddcafe ||
534*7c478bd9Sstevel@tonic-gate 	    val->rcv_next == (void *)0xbaddcafe ||
535*7c478bd9Sstevel@tonic-gate 	    val->rcv_prev == (void *)0xdeadbeef ||
536*7c478bd9Sstevel@tonic-gate 	    val->rcv_next == (void *)0xdeadbeef) {
537*7c478bd9Sstevel@tonic-gate 		if (data->v_bad_rctl++ == 0)
538*7c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", data->v_rctl_addr);
539*7c478bd9Sstevel@tonic-gate 		if (data->v_flags & RCV_VERBOSE)
540*7c478bd9Sstevel@tonic-gate 			mdb_printf("/ uninitialized or previously "
541*7c478bd9Sstevel@tonic-gate 			    "freed link at %p ", addr);
542*7c478bd9Sstevel@tonic-gate 	}
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	if (data->v_seen_cnt == 0) {
545*7c478bd9Sstevel@tonic-gate 		if (val->rcv_prev != NULL) {
546*7c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
547*7c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
548*7c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
549*7c478bd9Sstevel@tonic-gate 				mdb_printf("/ bad prev pointer at "
550*7c478bd9Sstevel@tonic-gate 				    "head ");
551*7c478bd9Sstevel@tonic-gate 		}
552*7c478bd9Sstevel@tonic-gate 	} else {
553*7c478bd9Sstevel@tonic-gate 		if ((uintptr_t)val->rcv_prev !=
554*7c478bd9Sstevel@tonic-gate 		    data->v_seen[data->v_seen_cnt - 1].s_ptr) {
555*7c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
556*7c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
557*7c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
558*7c478bd9Sstevel@tonic-gate 				mdb_printf("/ bad prev pointer at %p ",
559*7c478bd9Sstevel@tonic-gate 				    addr);
560*7c478bd9Sstevel@tonic-gate 		}
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 		if (data->v_seen[data->v_seen_cnt].s_val <
563*7c478bd9Sstevel@tonic-gate 		    data->v_seen[data->v_seen_cnt - 1].s_val) {
564*7c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
565*7c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
566*7c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
567*7c478bd9Sstevel@tonic-gate 				mdb_printf("/ ordering error at %p ",
568*7c478bd9Sstevel@tonic-gate 				    addr);
569*7c478bd9Sstevel@tonic-gate 		}
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	for (i = data->v_seen_cnt; i >= 0; i--) {
573*7c478bd9Sstevel@tonic-gate 		if (data->v_seen[i].s_ptr == (uintptr_t)val->rcv_next) {
574*7c478bd9Sstevel@tonic-gate 			if (data->v_bad_rctl++ == 0)
575*7c478bd9Sstevel@tonic-gate 				mdb_printf("%p ", data->v_rctl_addr);
576*7c478bd9Sstevel@tonic-gate 			if (data->v_flags & RCV_VERBOSE)
577*7c478bd9Sstevel@tonic-gate 				mdb_printf("/ circular next pointer "
578*7c478bd9Sstevel@tonic-gate 				    "at %p ", addr);
579*7c478bd9Sstevel@tonic-gate 			data->v_circularity_detected++;
580*7c478bd9Sstevel@tonic-gate 			break;
581*7c478bd9Sstevel@tonic-gate 		}
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	if (data->v_circularity_detected)
585*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	data->v_seen_cnt++;
588*7c478bd9Sstevel@tonic-gate 	if (data->v_seen_cnt >= data->v_seen_size) {
589*7c478bd9Sstevel@tonic-gate 		uint_t new_seen_size = data->v_seen_size * 2;
590*7c478bd9Sstevel@tonic-gate 		rctl_val_seen_t *tseen = mdb_zalloc(new_seen_size *
591*7c478bd9Sstevel@tonic-gate 		    sizeof (rctl_val_seen_t), UM_SLEEP | UM_GC);
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 		bcopy(data->v_seen, tseen, data->v_seen_size *
594*7c478bd9Sstevel@tonic-gate 		    sizeof (rctl_val_seen_t));
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 		data->v_seen = tseen;
597*7c478bd9Sstevel@tonic-gate 		data->v_seen_size = new_seen_size;
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
601*7c478bd9Sstevel@tonic-gate }
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate /*
604*7c478bd9Sstevel@tonic-gate  * Validate a rctl pointer by checking:
605*7c478bd9Sstevel@tonic-gate  *   - rctl_val_t's for that rctl form an ordered, non-circular list
606*7c478bd9Sstevel@tonic-gate  *   - the cursor points to a rctl_val_t within that list
607*7c478bd9Sstevel@tonic-gate  *   - there are no more than UINT64_MAX (or # specified by -n)
608*7c478bd9Sstevel@tonic-gate  *     rctl_val_t's in the list
609*7c478bd9Sstevel@tonic-gate  */
610*7c478bd9Sstevel@tonic-gate int
611*7c478bd9Sstevel@tonic-gate rctl_validate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
612*7c478bd9Sstevel@tonic-gate {
613*7c478bd9Sstevel@tonic-gate 	rctl_validate_data_t data;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	rctl_t r;
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	uint64_t long_threshold = UINT64_MAX;
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	/* Initialize validate data structure */
620*7c478bd9Sstevel@tonic-gate 	data.v_rctl_addr = addr;
621*7c478bd9Sstevel@tonic-gate 	data.v_flags = 0;
622*7c478bd9Sstevel@tonic-gate 	data.v_bad_rctl = 0;
623*7c478bd9Sstevel@tonic-gate 	data.v_seen_cnt = 0;
624*7c478bd9Sstevel@tonic-gate 	data.v_cursor_valid = 0;
625*7c478bd9Sstevel@tonic-gate 	data.v_circularity_detected = 0;
626*7c478bd9Sstevel@tonic-gate 	data.v_seen_size = 1;
627*7c478bd9Sstevel@tonic-gate 	data.v_seen = mdb_zalloc(data.v_seen_size * sizeof (rctl_val_seen_t),
628*7c478bd9Sstevel@tonic-gate 	    UM_SLEEP | UM_GC);
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
631*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
634*7c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, RCV_VERBOSE, &data.v_flags,
635*7c478bd9Sstevel@tonic-gate 	    'n', MDB_OPT_UINT64, &long_threshold,
636*7c478bd9Sstevel@tonic-gate 	    NULL) != argc)
637*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&r, sizeof (rctl_t), addr) != sizeof (rctl_t)) {
640*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read rctl structure at %p", addr);
641*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
642*7c478bd9Sstevel@tonic-gate 	}
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	data.v_cursor = r.rc_cursor;
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	if (data.v_cursor == NULL) {
647*7c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
648*7c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
649*7c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
650*7c478bd9Sstevel@tonic-gate 			mdb_printf("/ NULL cursor seen ");
651*7c478bd9Sstevel@tonic-gate 	} else if (data.v_cursor == (rctl_val_t *)0xbaddcafe) {
652*7c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
653*7c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
654*7c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
655*7c478bd9Sstevel@tonic-gate 			mdb_printf("/ uninitialized cursor seen ");
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	/* Walk through each val in this rctl for individual validation. */
659*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("rctl_val", (mdb_walk_cb_t)rctl_val_validate, &data,
660*7c478bd9Sstevel@tonic-gate 	    addr) == -1) {
661*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to walk all values for rctl_t %p", addr);
662*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
663*7c478bd9Sstevel@tonic-gate 	}
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	if (data.v_seen_cnt >= long_threshold) {
666*7c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
667*7c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
668*7c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
669*7c478bd9Sstevel@tonic-gate 			mdb_printf("/ sequence length = %d ",
670*7c478bd9Sstevel@tonic-gate 			    data.v_seen_cnt);
671*7c478bd9Sstevel@tonic-gate 	}
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	if (!data.v_cursor_valid) {
674*7c478bd9Sstevel@tonic-gate 		if (data.v_bad_rctl++ == 0)
675*7c478bd9Sstevel@tonic-gate 			mdb_printf("%p ", addr);
676*7c478bd9Sstevel@tonic-gate 		if (data.v_flags & RCV_VERBOSE)
677*7c478bd9Sstevel@tonic-gate 			mdb_printf("/ cursor outside sequence");
678*7c478bd9Sstevel@tonic-gate 	}
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	if (data.v_bad_rctl)
681*7c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	if (data.v_circularity_detected)
684*7c478bd9Sstevel@tonic-gate 		mdb_warn("circular list implies possible memory leak; "
685*7c478bd9Sstevel@tonic-gate 		    "recommend invoking ::findleaks");
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
688*7c478bd9Sstevel@tonic-gate }
689