4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 #include <mdb/mdb_param.h>
27 #include <mdb/mdb_modapi.h>
28 #include <mdb/mdb_ks.h>
35 #define ZONE_NAMELEN 20
37 #define ZONE_PATHLEN 32
39 #define ZONE_PATHLEN 40
43 * Names corresponding to zone_status_t values in sys/zone.h
45 char *zone_status_names
[] = {
46 "uninitialized", /* ZONE_IS_UNINITIALIZED */
47 "initialized", /* ZONE_IS_INITIALIZED */
48 "ready", /* ZONE_IS_READY */
49 "booting", /* ZONE_IS_BOOTING */
50 "running", /* ZONE_IS_RUNNING */
51 "shutting_down", /* ZONE_IS_SHUTTING_DOWN */
52 "empty", /* ZONE_IS_EMPTY */
53 "down", /* ZONE_IS_DOWN */
54 "dying", /* ZONE_IS_DYING */
55 "dead" /* ZONE_IS_DEAD */
59 zid_lookup_cb(uintptr_t addr
, const zone_t
*zone
, void *arg
)
61 zoneid_t zid
= *(uintptr_t *)arg
;
62 if (zone
->zone_id
== zid
)
63 mdb_printf("%p\n", addr
);
70 zid2zone(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
72 if (!(flags
& DCMD_ADDRSPEC
) || argc
!= 0)
75 if (mdb_walk("zone", (mdb_walk_cb_t
)zid_lookup_cb
, &addr
) == -1) {
76 mdb_warn("failed to walk zone");
84 zoneprt(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
87 char name
[ZONE_NAMELEN
];
88 char path
[ZONE_PATHLEN
];
96 if (!(flags
& DCMD_ADDRSPEC
)) {
97 if (mdb_walk_dcmd("zone", "zone", argc
, argv
) == -1) {
98 mdb_warn("can't walk zones");
105 * Get the optional -r (reference counts) and -v (verbose output)
110 if (argc
> 0 && mdb_getopts(argc
, argv
, 'v', MDB_OPT_SETBITS
, TRUE
,
111 &vopt_given
, 'r', MDB_OPT_SETBITS
, TRUE
, &ropt_given
, NULL
) != argc
)
115 * -v can only be specified with -r.
117 if (vopt_given
== TRUE
&& ropt_given
== FALSE
)
121 * Print a table header, if necessary.
123 if (DCMD_HDRSPEC(flags
)) {
124 if (ropt_given
== FALSE
)
125 mdb_printf("%<u>%?s %6s %-13s %-20s %-s%</u>\n",
126 "ADDR", "ID", "STATUS", "NAME", "PATH");
128 mdb_printf("%<u>%?s %6s %10s %10s %-20s%</u>\n",
129 "ADDR", "ID", "REFS", "CREFS", "NAME");
133 * Read the zone_t structure at the given address and read its name.
135 if (mdb_vread(&zn
, sizeof (zone_t
), addr
) == -1) {
136 mdb_warn("can't read zone_t structure at %p", addr
);
139 len
= mdb_readstr(name
, ZONE_NAMELEN
, (uintptr_t)zn
.zone_name
);
141 if (len
== ZONE_NAMELEN
)
142 (void) strcpy(&name
[len
- 4], "...");
144 (void) strcpy(name
, "??");
147 if (ropt_given
== FALSE
) {
152 * Fetch the zone's path and print the results.
154 len
= mdb_readstr(path
, ZONE_PATHLEN
,
155 (uintptr_t)zn
.zone_rootpath
);
157 if (len
== ZONE_PATHLEN
)
158 (void) strcpy(&path
[len
- 4], "...");
160 (void) strcpy(path
, "??");
162 if (zn
.zone_status
>= ZONE_IS_UNINITIALIZED
&& zn
.zone_status
<=
164 statusp
= zone_status_names
[zn
.zone_status
];
167 mdb_printf("%0?p %6d %-13s %-20s %s\n", addr
, zn
.zone_id
,
168 statusp
, name
, path
);
171 * Display the zone's reference counts.
172 * Display the zone's subsystem-specific reference counts if
173 * the user specified the '-v' option.
175 mdb_printf("%0?p %6d %10u %10u %-20s\n", addr
, zn
.zone_id
,
176 zn
.zone_ref
, zn
.zone_cred_ref
, name
);
177 if (vopt_given
== TRUE
) {
178 GElf_Sym subsys_names_sym
;
179 uintptr_t **zone_ref_subsys_names
;
184 * Read zone_ref_subsys_names from the kernel image.
186 if (mdb_lookup_by_name("zone_ref_subsys_names",
187 &subsys_names_sym
) != 0) {
188 mdb_warn("can't find zone_ref_subsys_names");
191 if (subsys_names_sym
.st_size
!= ZONE_REF_NUM_SUBSYS
*
193 mdb_warn("number of subsystems in target "
194 "differs from what mdb expects (mismatched"
195 " kernel versions?)");
196 if (subsys_names_sym
.st_size
<
197 ZONE_REF_NUM_SUBSYS
* sizeof (char *))
198 num_subsys
= subsys_names_sym
.st_size
/
201 num_subsys
= ZONE_REF_NUM_SUBSYS
;
203 num_subsys
= ZONE_REF_NUM_SUBSYS
;
205 if ((zone_ref_subsys_names
= mdb_alloc(
206 subsys_names_sym
.st_size
, UM_GC
)) == NULL
) {
207 mdb_warn("out of memory");
210 if (mdb_readvar(zone_ref_subsys_names
,
211 "zone_ref_subsys_names") == -1) {
212 mdb_warn("can't find zone_ref_subsys_names");
217 * Display each subsystem's reference count if it's
221 for (n
= 0; n
< num_subsys
; ++n
) {
222 char subsys_name
[16];
225 * Skip subsystems lacking outstanding
228 if (zn
.zone_subsys_ref
[n
] == 0)
232 * Each subsystem's name must be read from
233 * the target's image.
235 if (mdb_readstr(subsys_name
,
236 sizeof (subsys_name
),
237 (uintptr_t)zone_ref_subsys_names
[n
]) ==
239 mdb_warn("unable to read subsystem name"
240 " from zone_ref_subsys_names[%u]",
244 mdb_printf("%15s: %10u\n", subsys_name
,
245 zn
.zone_subsys_ref
[n
]);
254 zone_walk_init(mdb_walk_state_t
*wsp
)
258 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
259 if (mdb_lookup_by_name("zone_active", &sym
) == -1) {
260 mdb_warn("failed to find 'zone_active'");
263 wsp
->walk_addr
= (uintptr_t)sym
.st_value
;
265 if (mdb_layered_walk("list", wsp
) == -1) {
266 mdb_warn("couldn't walk 'list'");
273 zone_walk_step(mdb_walk_state_t
*wsp
)
275 return (wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_layer
,
280 zsd_walk_init(mdb_walk_state_t
*wsp
)
282 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
283 mdb_warn("global walk not supported\n");
286 wsp
->walk_addr
+= offsetof(struct zone
, zone_zsd
);
287 if (mdb_layered_walk("list", wsp
) == -1) {
288 mdb_warn("couldn't walk 'list'");
295 zsd_walk_step(mdb_walk_state_t
*wsp
)
297 return (wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_layer
,
302 * Helper structure used when walking ZSD entries via zsd().
305 uint_t keygiven
; /* Was a key specified (are we */
306 /* searching for a specific ZSD */
308 zone_key_t key
; /* Key of ZSD for which we're looking */
309 uint_t found
; /* Was the specific ZSD entry found? */
310 uint_t voptgiven
; /* Display verbose information? */
314 * Helper function for zsd() that displays information from a single ZSD struct.
315 * 'datap' must point to a valid zsd_cb_data struct.
319 zsd_print(uintptr_t addrp
, const void * datap
, void * privatep
)
321 struct zsd_entry entry
;
322 struct zsd_cb_data
*cbdp
;
324 if (mdb_vread(&entry
, sizeof (entry
), addrp
) == -1) {
325 mdb_warn("couldn't read zsd_entry at %p", addrp
);
328 cbdp
= (struct zsd_cb_data
*)privatep
;
331 * Are we looking for a single entry specified by a key? Then make sure
332 * that the current ZSD's key is what we're looking for.
334 if (cbdp
->keygiven
== TRUE
&& cbdp
->key
!= entry
.zsd_key
)
337 mdb_printf("%?x %0?p %8x\n", entry
.zsd_key
, entry
.zsd_data
,
339 if (cbdp
->voptgiven
== TRUE
)
340 mdb_printf(" Create CB: %a\n Shutdown CB: %a\n"
341 " Destroy CB: %a\n", entry
.zsd_create
,
342 entry
.zsd_shutdown
, entry
.zsd_destroy
);
343 if (cbdp
->keygiven
== TRUE
) {
351 zsd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
354 const mdb_arg_t
*argp
;
356 struct zsd_cb_data cbd
;
357 char name
[ZONE_NAMELEN
];
361 * Walk all zones if necessary.
365 if ((flags
& DCMD_ADDRSPEC
) == 0) {
366 if (mdb_walk_dcmd("zone", "zsd", argc
, argv
) == -1) {
367 mdb_warn("failed to walk zone\n");
374 * Make sure a zone_t can be read from the specified address.
376 if (mdb_vread(&zone
, sizeof (zone
), addr
) == -1) {
377 mdb_warn("couldn't read zone_t at %p", (void *)addr
);
382 * Get the optional arguments (key or -v or both). Note that
383 * mdb_getopts() will not parse a key argument because it is not
384 * preceded by an option letter. We'll get around this by requiring
385 * that all options precede the optional key argument.
387 cbd
.keygiven
= FALSE
;
388 cbd
.voptgiven
= FALSE
;
389 if (argc
> 0 && (argcindex
= mdb_getopts(argc
, argv
, 'v',
390 MDB_OPT_SETBITS
, TRUE
, &cbd
.voptgiven
, NULL
)) != argc
) {
392 * No options may appear after the key.
394 if (argcindex
!= argc
- 1)
398 * The missed argument should be a key.
400 argp
= &argv
[argcindex
];
401 if (argp
->a_type
== MDB_TYPE_IMMEDIATE
)
402 cbd
.key
= argp
->a_un
.a_val
;
404 cbd
.key
= mdb_strtoull(argp
->a_un
.a_str
);
410 * Prepare to output the specified zone's ZSD information.
412 if (DCMD_HDRSPEC(flags
))
413 mdb_printf("%<u>%-20s %?s %?s %8s%</u>\n", "ZONE", "KEY",
415 len
= mdb_readstr(name
, ZONE_NAMELEN
, (uintptr_t)zone
.zone_name
);
417 if (len
== ZONE_NAMELEN
)
418 (void) strcpy(&name
[len
- 4], "...");
420 (void) strcpy(name
, "??");
422 mdb_printf("%-20s ", name
);
425 * Display the requested ZSD entries.
428 if (mdb_pwalk("zsd", zsd_print
, &cbd
, addr
) != 0) {
429 mdb_warn("failed to walk zsd\n");
433 if (cbd
.keygiven
== TRUE
&& cbd
.found
== FALSE
) {
434 mdb_printf("no corresponding ZSD entry found\n");