xref: /titanic_44/usr/src/cmd/mdb/common/modules/genunix/zone.c (revision 589efa9501f3347f21e60905a96ca39427169e10)
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
55b9a3b50Sjv227347  * Common Development and Distribution License (the "License").
65b9a3b50Sjv227347  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22a19609f8Sjv227347  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23*589efa95SRobert Mustacchi  * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <mdb/mdb_param.h>
277c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
287c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h>
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include "zone.h"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <stddef.h>
337c478bd9Sstevel@tonic-gate #include <sys/zone.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #define	ZONE_NAMELEN	20
367c478bd9Sstevel@tonic-gate #ifdef _LP64
377c478bd9Sstevel@tonic-gate #define	ZONE_PATHLEN	32
387c478bd9Sstevel@tonic-gate #else
397c478bd9Sstevel@tonic-gate #define	ZONE_PATHLEN	40
407c478bd9Sstevel@tonic-gate #endif
417c478bd9Sstevel@tonic-gate 
42a19609f8Sjv227347 /*
43a19609f8Sjv227347  * Names corresponding to zone_status_t values in sys/zone.h
44a19609f8Sjv227347  */
45a19609f8Sjv227347 char *zone_status_names[] = {
46a19609f8Sjv227347 	"uninitialized",	/* ZONE_IS_UNINITIALIZED */
47a19609f8Sjv227347 	"initialized",		/* ZONE_IS_INITIALIZED */
48a19609f8Sjv227347 	"ready",		/* ZONE_IS_READY */
49a19609f8Sjv227347 	"booting",		/* ZONE_IS_BOOTING */
50a19609f8Sjv227347 	"running",		/* ZONE_IS_RUNNING */
51a19609f8Sjv227347 	"shutting_down",	/* ZONE_IS_SHUTTING_DOWN */
52a19609f8Sjv227347 	"empty",		/* ZONE_IS_EMPTY */
53a19609f8Sjv227347 	"down",			/* ZONE_IS_DOWN */
54a19609f8Sjv227347 	"dying",		/* ZONE_IS_DYING */
55a19609f8Sjv227347 	"dead"			/* ZONE_IS_DEAD */
56a19609f8Sjv227347 };
57a19609f8Sjv227347 
58*589efa95SRobert Mustacchi static int
zid_lookup_cb(uintptr_t addr,const zone_t * zone,void * arg)59*589efa95SRobert Mustacchi zid_lookup_cb(uintptr_t addr, const zone_t *zone, void *arg)
60*589efa95SRobert Mustacchi {
61*589efa95SRobert Mustacchi 	zoneid_t zid = *(uintptr_t *)arg;
62*589efa95SRobert Mustacchi 	if (zone->zone_id == zid)
63*589efa95SRobert Mustacchi 		mdb_printf("%p\n", addr);
64*589efa95SRobert Mustacchi 
65*589efa95SRobert Mustacchi 	return (WALK_NEXT);
66*589efa95SRobert Mustacchi }
67*589efa95SRobert Mustacchi 
68*589efa95SRobert Mustacchi /*ARGSUSED*/
69*589efa95SRobert Mustacchi int
zid2zone(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)70*589efa95SRobert Mustacchi zid2zone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
71*589efa95SRobert Mustacchi {
72*589efa95SRobert Mustacchi 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
73*589efa95SRobert Mustacchi 		return (DCMD_USAGE);
74*589efa95SRobert Mustacchi 
75*589efa95SRobert Mustacchi 	if (mdb_walk("zone", (mdb_walk_cb_t)zid_lookup_cb, &addr) == -1) {
76*589efa95SRobert Mustacchi 		mdb_warn("failed to walk zone");
77*589efa95SRobert Mustacchi 		return (DCMD_ERR);
78*589efa95SRobert Mustacchi 	}
79*589efa95SRobert Mustacchi 
80*589efa95SRobert Mustacchi 	return (DCMD_OK);
81*589efa95SRobert Mustacchi }
82*589efa95SRobert Mustacchi 
837c478bd9Sstevel@tonic-gate int
zoneprt(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)847c478bd9Sstevel@tonic-gate zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	zone_t zn;
877c478bd9Sstevel@tonic-gate 	char name[ZONE_NAMELEN];
887c478bd9Sstevel@tonic-gate 	char path[ZONE_PATHLEN];
897c478bd9Sstevel@tonic-gate 	int len;
90a19609f8Sjv227347 	uint_t vopt_given;
91a19609f8Sjv227347 	uint_t ropt_given;
927c478bd9Sstevel@tonic-gate 
93a19609f8Sjv227347 	if (argc > 2)
947c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
977c478bd9Sstevel@tonic-gate 		if (mdb_walk_dcmd("zone", "zone", argc, argv) == -1) {
987c478bd9Sstevel@tonic-gate 			mdb_warn("can't walk zones");
997c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
1007c478bd9Sstevel@tonic-gate 		}
1017c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
1027c478bd9Sstevel@tonic-gate 	}
103a19609f8Sjv227347 
104a19609f8Sjv227347 	/*
105a19609f8Sjv227347 	 * Get the optional -r (reference counts) and -v (verbose output)
106a19609f8Sjv227347 	 * arguments.
107a19609f8Sjv227347 	 */
108a19609f8Sjv227347 	vopt_given = FALSE;
109a19609f8Sjv227347 	ropt_given = FALSE;
110a19609f8Sjv227347 	if (argc > 0 && mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE,
111a19609f8Sjv227347 	    &vopt_given, 'r', MDB_OPT_SETBITS, TRUE, &ropt_given, NULL) != argc)
112a19609f8Sjv227347 		return (DCMD_USAGE);
113a19609f8Sjv227347 
114a19609f8Sjv227347 	/*
115a19609f8Sjv227347 	 * -v can only be specified with -r.
116a19609f8Sjv227347 	 */
117a19609f8Sjv227347 	if (vopt_given == TRUE && ropt_given == FALSE)
118a19609f8Sjv227347 		return (DCMD_USAGE);
119a19609f8Sjv227347 
120a19609f8Sjv227347 	/*
121a19609f8Sjv227347 	 * Print a table header, if necessary.
122a19609f8Sjv227347 	 */
1237c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
124a19609f8Sjv227347 		if (ropt_given == FALSE)
125a19609f8Sjv227347 			mdb_printf("%<u>%?s %6s %-13s %-20s %-s%</u>\n",
126a19609f8Sjv227347 			    "ADDR", "ID", "STATUS", "NAME", "PATH");
127a19609f8Sjv227347 		else
128a19609f8Sjv227347 			mdb_printf("%<u>%?s %6s %10s %10s %-20s%</u>\n",
129a19609f8Sjv227347 			    "ADDR", "ID", "REFS", "CREFS", "NAME");
1307c478bd9Sstevel@tonic-gate 	}
131a19609f8Sjv227347 
132a19609f8Sjv227347 	/*
133a19609f8Sjv227347 	 * Read the zone_t structure at the given address and read its name.
134a19609f8Sjv227347 	 */
1357c478bd9Sstevel@tonic-gate 	if (mdb_vread(&zn, sizeof (zone_t), addr) == -1) {
1367c478bd9Sstevel@tonic-gate 		mdb_warn("can't read zone_t structure at %p", addr);
1377c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 	len = mdb_readstr(name, ZONE_NAMELEN, (uintptr_t)zn.zone_name);
1407c478bd9Sstevel@tonic-gate 	if (len > 0) {
1417c478bd9Sstevel@tonic-gate 		if (len == ZONE_NAMELEN)
1427c478bd9Sstevel@tonic-gate 			(void) strcpy(&name[len - 4], "...");
1437c478bd9Sstevel@tonic-gate 	} else {
1447c478bd9Sstevel@tonic-gate 		(void) strcpy(name, "??");
1457c478bd9Sstevel@tonic-gate 	}
146a19609f8Sjv227347 
147a19609f8Sjv227347 	if (ropt_given == FALSE) {
148a19609f8Sjv227347 		char *statusp;
149a19609f8Sjv227347 
150a19609f8Sjv227347 		/*
151a19609f8Sjv227347 		 * Default display
152a19609f8Sjv227347 		 * Fetch the zone's path and print the results.
153a19609f8Sjv227347 		 */
154a19609f8Sjv227347 		len = mdb_readstr(path, ZONE_PATHLEN,
155a19609f8Sjv227347 		    (uintptr_t)zn.zone_rootpath);
1567c478bd9Sstevel@tonic-gate 		if (len > 0) {
1577c478bd9Sstevel@tonic-gate 			if (len == ZONE_PATHLEN)
1587c478bd9Sstevel@tonic-gate 				(void) strcpy(&path[len - 4], "...");
1597c478bd9Sstevel@tonic-gate 		} else {
1607c478bd9Sstevel@tonic-gate 			(void) strcpy(path, "??");
1617c478bd9Sstevel@tonic-gate 		}
162a19609f8Sjv227347 		if (zn.zone_status >= ZONE_IS_UNINITIALIZED && zn.zone_status <=
163a19609f8Sjv227347 		    ZONE_IS_DEAD)
164a19609f8Sjv227347 			statusp = zone_status_names[zn.zone_status];
165a19609f8Sjv227347 		else
166a19609f8Sjv227347 			statusp = "???";
167a19609f8Sjv227347 		mdb_printf("%0?p %6d %-13s %-20s %s\n", addr, zn.zone_id,
168a19609f8Sjv227347 		    statusp, name, path);
169a19609f8Sjv227347 	} else {
170a19609f8Sjv227347 		/*
171a19609f8Sjv227347 		 * Display the zone's reference counts.
172a19609f8Sjv227347 		 * Display the zone's subsystem-specific reference counts if
173a19609f8Sjv227347 		 * the user specified the '-v' option.
174a19609f8Sjv227347 		 */
175a19609f8Sjv227347 		mdb_printf("%0?p %6d %10u %10u %-20s\n", addr, zn.zone_id,
176a19609f8Sjv227347 		    zn.zone_ref, zn.zone_cred_ref, name);
177a19609f8Sjv227347 		if (vopt_given == TRUE) {
178a19609f8Sjv227347 			GElf_Sym subsys_names_sym;
179a19609f8Sjv227347 			uintptr_t **zone_ref_subsys_names;
180a19609f8Sjv227347 			uint_t num_subsys;
181a19609f8Sjv227347 			uint_t n;
182a19609f8Sjv227347 
183a19609f8Sjv227347 			/*
184a19609f8Sjv227347 			 * Read zone_ref_subsys_names from the kernel image.
185a19609f8Sjv227347 			 */
186a19609f8Sjv227347 			if (mdb_lookup_by_name("zone_ref_subsys_names",
187a19609f8Sjv227347 			    &subsys_names_sym) != 0) {
188a19609f8Sjv227347 				mdb_warn("can't find zone_ref_subsys_names");
189a19609f8Sjv227347 				return (DCMD_ERR);
190a19609f8Sjv227347 			}
191a19609f8Sjv227347 			if (subsys_names_sym.st_size != ZONE_REF_NUM_SUBSYS *
192a19609f8Sjv227347 			    sizeof (char *)) {
193a19609f8Sjv227347 				mdb_warn("number of subsystems in target "
194a19609f8Sjv227347 				    "differs from what mdb expects (mismatched"
195a19609f8Sjv227347 				    " kernel versions?)");
196a19609f8Sjv227347 				if (subsys_names_sym.st_size <
197a19609f8Sjv227347 				    ZONE_REF_NUM_SUBSYS * sizeof (char *))
198a19609f8Sjv227347 					num_subsys = subsys_names_sym.st_size /
199a19609f8Sjv227347 					    sizeof (char *);
200a19609f8Sjv227347 				else
201a19609f8Sjv227347 					num_subsys = ZONE_REF_NUM_SUBSYS;
202a19609f8Sjv227347 			} else {
203a19609f8Sjv227347 				num_subsys = ZONE_REF_NUM_SUBSYS;
204a19609f8Sjv227347 			}
205a19609f8Sjv227347 			if ((zone_ref_subsys_names = mdb_alloc(
206a19609f8Sjv227347 			    subsys_names_sym.st_size, UM_GC)) == NULL) {
207a19609f8Sjv227347 				mdb_warn("out of memory");
208a19609f8Sjv227347 				return (DCMD_ERR);
209a19609f8Sjv227347 			}
210a19609f8Sjv227347 			if (mdb_readvar(zone_ref_subsys_names,
211a19609f8Sjv227347 			    "zone_ref_subsys_names") == -1) {
212a19609f8Sjv227347 				mdb_warn("can't find zone_ref_subsys_names");
213a19609f8Sjv227347 				return (DCMD_ERR);
214a19609f8Sjv227347 			}
215a19609f8Sjv227347 
216a19609f8Sjv227347 			/*
217a19609f8Sjv227347 			 * Display each subsystem's reference count if it's
218a19609f8Sjv227347 			 * nonzero.
219a19609f8Sjv227347 			 */
220a19609f8Sjv227347 			mdb_inc_indent(7);
221a19609f8Sjv227347 			for (n = 0; n < num_subsys; ++n) {
222a19609f8Sjv227347 				char subsys_name[16];
223a19609f8Sjv227347 
224a19609f8Sjv227347 				/*
225a19609f8Sjv227347 				 * Skip subsystems lacking outstanding
226a19609f8Sjv227347 				 * references.
227a19609f8Sjv227347 				 */
228a19609f8Sjv227347 				if (zn.zone_subsys_ref[n] == 0)
229a19609f8Sjv227347 					continue;
230a19609f8Sjv227347 
231a19609f8Sjv227347 				/*
232a19609f8Sjv227347 				 * Each subsystem's name must be read from
233a19609f8Sjv227347 				 * the target's image.
234a19609f8Sjv227347 				 */
235a19609f8Sjv227347 				if (mdb_readstr(subsys_name,
236a19609f8Sjv227347 				    sizeof (subsys_name),
237a19609f8Sjv227347 				    (uintptr_t)zone_ref_subsys_names[n]) ==
238a19609f8Sjv227347 				    -1) {
239a19609f8Sjv227347 					mdb_warn("unable to read subsystem name"
240a19609f8Sjv227347 					    " from zone_ref_subsys_names[%u]",
241a19609f8Sjv227347 					    n);
242a19609f8Sjv227347 					return (DCMD_ERR);
243a19609f8Sjv227347 				}
244a19609f8Sjv227347 				mdb_printf("%15s: %10u\n", subsys_name,
245a19609f8Sjv227347 				    zn.zone_subsys_ref[n]);
246a19609f8Sjv227347 			}
247a19609f8Sjv227347 			mdb_dec_indent(7);
248a19609f8Sjv227347 		}
249a19609f8Sjv227347 	}
2507c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate int
zone_walk_init(mdb_walk_state_t * wsp)2547c478bd9Sstevel@tonic-gate zone_walk_init(mdb_walk_state_t *wsp)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2597c478bd9Sstevel@tonic-gate 		if (mdb_lookup_by_name("zone_active", &sym) == -1) {
2607c478bd9Sstevel@tonic-gate 			mdb_warn("failed to find 'zone_active'");
2617c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)sym.st_value;
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 	if (mdb_layered_walk("list", wsp) == -1) {
2667c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk 'list'");
2677c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate int
zone_walk_step(mdb_walk_state_t * wsp)2737c478bd9Sstevel@tonic-gate zone_walk_step(mdb_walk_state_t *wsp)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
2767c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata));
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate int
zsd_walk_init(mdb_walk_state_t * wsp)2807c478bd9Sstevel@tonic-gate zsd_walk_init(mdb_walk_state_t *wsp)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2837c478bd9Sstevel@tonic-gate 		mdb_warn("global walk not supported\n");
2847c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	wsp->walk_addr += offsetof(struct zone, zone_zsd);
2877c478bd9Sstevel@tonic-gate 	if (mdb_layered_walk("list", wsp) == -1) {
2887c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk 'list'");
2897c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate int
zsd_walk_step(mdb_walk_state_t * wsp)2957c478bd9Sstevel@tonic-gate zsd_walk_step(mdb_walk_state_t *wsp)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
2987c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata));
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3015b9a3b50Sjv227347 /*
3025b9a3b50Sjv227347  * Helper structure used when walking ZSD entries via zsd().
3035b9a3b50Sjv227347  */
3047c478bd9Sstevel@tonic-gate struct zsd_cb_data {
3055b9a3b50Sjv227347 	uint_t		keygiven;	/* Was a key specified (are we */
3065b9a3b50Sjv227347 					/* searching for a specific ZSD */
3075b9a3b50Sjv227347 					/* entry)? */
3085b9a3b50Sjv227347 	zone_key_t	key;		/* Key of ZSD for which we're looking */
3095b9a3b50Sjv227347 	uint_t		found;		/* Was the specific ZSD entry found? */
3105b9a3b50Sjv227347 	uint_t		voptgiven;	/* Display verbose information? */
3117c478bd9Sstevel@tonic-gate };
3127c478bd9Sstevel@tonic-gate 
3135b9a3b50Sjv227347 /*
3145b9a3b50Sjv227347  * Helper function for zsd() that displays information from a single ZSD struct.
3155b9a3b50Sjv227347  * 'datap' must point to a valid zsd_cb_data struct.
3165b9a3b50Sjv227347  */
3177c478bd9Sstevel@tonic-gate /* ARGSUSED */
3187c478bd9Sstevel@tonic-gate static int
zsd_print(uintptr_t addrp,const void * datap,void * privatep)3195b9a3b50Sjv227347 zsd_print(uintptr_t addrp, const void * datap, void * privatep)
3207c478bd9Sstevel@tonic-gate {
3215b9a3b50Sjv227347 	struct zsd_entry entry;
3225b9a3b50Sjv227347 	struct zsd_cb_data *cbdp;
3237c478bd9Sstevel@tonic-gate 
3245b9a3b50Sjv227347 	if (mdb_vread(&entry, sizeof (entry), addrp) == -1) {
3255b9a3b50Sjv227347 		mdb_warn("couldn't read zsd_entry at %p", addrp);
3267c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3277c478bd9Sstevel@tonic-gate 	}
3285b9a3b50Sjv227347 	cbdp = (struct zsd_cb_data *)privatep;
3295b9a3b50Sjv227347 
3305b9a3b50Sjv227347 	/*
3315b9a3b50Sjv227347 	 * Are we looking for a single entry specified by a key?  Then make sure
3325b9a3b50Sjv227347 	 * that the current ZSD's key is what we're looking for.
3335b9a3b50Sjv227347 	 */
3345b9a3b50Sjv227347 	if (cbdp->keygiven == TRUE && cbdp->key != entry.zsd_key)
3357c478bd9Sstevel@tonic-gate 		return (WALK_NEXT);
3365b9a3b50Sjv227347 
3375b9a3b50Sjv227347 	mdb_printf("%?x %0?p %8x\n", entry.zsd_key, entry.zsd_data,
3385b9a3b50Sjv227347 	    entry.zsd_flags);
3395b9a3b50Sjv227347 	if (cbdp->voptgiven == TRUE)
3405b9a3b50Sjv227347 		mdb_printf("    Create CB:   %a\n    Shutdown CB: %a\n"
3415b9a3b50Sjv227347 		    "    Destroy CB:  %a\n", entry.zsd_create,
3425b9a3b50Sjv227347 		    entry.zsd_shutdown, entry.zsd_destroy);
3435b9a3b50Sjv227347 	if (cbdp->keygiven == TRUE) {
3445b9a3b50Sjv227347 		cbdp->found = TRUE;
3457c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
3467c478bd9Sstevel@tonic-gate 	}
3475b9a3b50Sjv227347 	return (WALK_NEXT);
3485b9a3b50Sjv227347 }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate int
zsd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3517c478bd9Sstevel@tonic-gate zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	zone_t zone;
3545b9a3b50Sjv227347 	const mdb_arg_t *argp;
3555b9a3b50Sjv227347 	int argcindex;
3567c478bd9Sstevel@tonic-gate 	struct zsd_cb_data cbd;
3575b9a3b50Sjv227347 	char name[ZONE_NAMELEN];
3585b9a3b50Sjv227347 	int len;
3597c478bd9Sstevel@tonic-gate 
3605b9a3b50Sjv227347 	/*
3615b9a3b50Sjv227347 	 * Walk all zones if necessary.
3625b9a3b50Sjv227347 	 */
3635b9a3b50Sjv227347 	if (argc > 2)
3647c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
3655b9a3b50Sjv227347 	if ((flags & DCMD_ADDRSPEC) == 0) {
3665b9a3b50Sjv227347 		if (mdb_walk_dcmd("zone", "zsd", argc, argv) == -1) {
3675b9a3b50Sjv227347 			mdb_warn("failed to walk zone\n");
3685b9a3b50Sjv227347 			return (DCMD_ERR);
3695b9a3b50Sjv227347 		}
3705b9a3b50Sjv227347 		return (DCMD_OK);
3715b9a3b50Sjv227347 	}
3725b9a3b50Sjv227347 
3735b9a3b50Sjv227347 	/*
3745b9a3b50Sjv227347 	 * Make sure a zone_t can be read from the specified address.
3755b9a3b50Sjv227347 	 */
3765b9a3b50Sjv227347 	if (mdb_vread(&zone, sizeof (zone), addr) == -1) {
3775b9a3b50Sjv227347 		mdb_warn("couldn't read zone_t at %p", (void *)addr);
3785b9a3b50Sjv227347 		return (DCMD_ERR);
3795b9a3b50Sjv227347 	}
3805b9a3b50Sjv227347 
3815b9a3b50Sjv227347 	/*
3825b9a3b50Sjv227347 	 * Get the optional arguments (key or -v or both).  Note that
3835b9a3b50Sjv227347 	 * mdb_getopts() will not parse a key argument because it is not
3845b9a3b50Sjv227347 	 * preceded by an option letter.  We'll get around this by requiring
3855b9a3b50Sjv227347 	 * that all options precede the optional key argument.
3865b9a3b50Sjv227347 	 */
3875b9a3b50Sjv227347 	cbd.keygiven = FALSE;
3885b9a3b50Sjv227347 	cbd.voptgiven = FALSE;
3895b9a3b50Sjv227347 	if (argc > 0 && (argcindex = mdb_getopts(argc, argv, 'v',
3905b9a3b50Sjv227347 	    MDB_OPT_SETBITS, TRUE, &cbd.voptgiven, NULL)) != argc) {
3915b9a3b50Sjv227347 		/*
3925b9a3b50Sjv227347 		 * No options may appear after the key.
3935b9a3b50Sjv227347 		 */
3945b9a3b50Sjv227347 		if (argcindex != argc - 1)
3955b9a3b50Sjv227347 			return (DCMD_USAGE);
3965b9a3b50Sjv227347 
3975b9a3b50Sjv227347 		/*
3985b9a3b50Sjv227347 		 * The missed argument should be a key.
3995b9a3b50Sjv227347 		 */
4005b9a3b50Sjv227347 		argp = &argv[argcindex];
4017c478bd9Sstevel@tonic-gate 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
4025b9a3b50Sjv227347 			cbd.key = argp->a_un.a_val;
4037c478bd9Sstevel@tonic-gate 		else
4045b9a3b50Sjv227347 			cbd.key = mdb_strtoull(argp->a_un.a_str);
4055b9a3b50Sjv227347 		cbd.keygiven = TRUE;
4065b9a3b50Sjv227347 		cbd.found = FALSE;
4077c478bd9Sstevel@tonic-gate 	}
4085b9a3b50Sjv227347 
4095b9a3b50Sjv227347 	/*
4105b9a3b50Sjv227347 	 * Prepare to output the specified zone's ZSD information.
4115b9a3b50Sjv227347 	 */
4125b9a3b50Sjv227347 	if (DCMD_HDRSPEC(flags))
4135b9a3b50Sjv227347 		mdb_printf("%<u>%-20s %?s %?s %8s%</u>\n", "ZONE", "KEY",
4145b9a3b50Sjv227347 		    "VALUE", "FLAGS");
4155b9a3b50Sjv227347 	len = mdb_readstr(name, ZONE_NAMELEN, (uintptr_t)zone.zone_name);
4165b9a3b50Sjv227347 	if (len > 0) {
4175b9a3b50Sjv227347 		if (len == ZONE_NAMELEN)
4185b9a3b50Sjv227347 			(void) strcpy(&name[len - 4], "...");
4195b9a3b50Sjv227347 	} else {
4205b9a3b50Sjv227347 		(void) strcpy(name, "??");
4215b9a3b50Sjv227347 	}
4225b9a3b50Sjv227347 	mdb_printf("%-20s ", name);
4235b9a3b50Sjv227347 
4245b9a3b50Sjv227347 	/*
4255b9a3b50Sjv227347 	 * Display the requested ZSD entries.
4265b9a3b50Sjv227347 	 */
4275b9a3b50Sjv227347 	mdb_inc_indent(21);
4285b9a3b50Sjv227347 	if (mdb_pwalk("zsd", zsd_print, &cbd, addr) != 0) {
4297c478bd9Sstevel@tonic-gate 		mdb_warn("failed to walk zsd\n");
4305b9a3b50Sjv227347 		mdb_dec_indent(21);
4317c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4327c478bd9Sstevel@tonic-gate 	}
4335b9a3b50Sjv227347 	if (cbd.keygiven == TRUE && cbd.found == FALSE) {
4345b9a3b50Sjv227347 		mdb_printf("no corresponding ZSD entry found\n");
4355b9a3b50Sjv227347 		mdb_dec_indent(21);
4367c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4377c478bd9Sstevel@tonic-gate 	}
4385b9a3b50Sjv227347 	mdb_dec_indent(21);
4397c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
4407c478bd9Sstevel@tonic-gate }
441