xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/nvpair.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/sysinfo.h>
30*0Sstevel@tonic-gate #include <sys/nvpair.h>
31*0Sstevel@tonic-gate #include <sys/nvpair_impl.h>
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <ctype.h>
34*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include "nvpair.h"
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #define	NVPAIR_VALUE_INDENT	4
39*0Sstevel@tonic-gate #define	NELEM(a)		(sizeof (a) / sizeof ((a)[0]))
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * nvpair walker
43*0Sstevel@tonic-gate  */
44*0Sstevel@tonic-gate int
45*0Sstevel@tonic-gate nvpair_walk_init(mdb_walk_state_t *wsp)
46*0Sstevel@tonic-gate {
47*0Sstevel@tonic-gate 	nvlist_t nvlist;
48*0Sstevel@tonic-gate 	nvpriv_t nvpriv;
49*0Sstevel@tonic-gate 	i_nvp_t *tmp;
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
52*0Sstevel@tonic-gate 		mdb_warn("nvpair does not support global walks\n");
53*0Sstevel@tonic-gate 		return (WALK_ERR);
54*0Sstevel@tonic-gate 	}
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate 	if (mdb_vread(&nvlist, sizeof (nvlist), wsp->walk_addr) == -1) {
57*0Sstevel@tonic-gate 		mdb_warn("failed to read nvlist at %p", wsp->walk_addr);
58*0Sstevel@tonic-gate 		return (WALK_ERR);
59*0Sstevel@tonic-gate 	}
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	if (mdb_vread(&nvpriv, sizeof (nvpriv), nvlist.nvl_priv) == -1) {
62*0Sstevel@tonic-gate 		mdb_warn("failed to read nvpriv at %p", nvlist.nvl_priv);
63*0Sstevel@tonic-gate 		return (WALK_ERR);
64*0Sstevel@tonic-gate 	}
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 	tmp = (i_nvp_t *)nvpriv.nvp_list;
67*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)tmp;
68*0Sstevel@tonic-gate 	return (WALK_NEXT);
69*0Sstevel@tonic-gate }
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate int
72*0Sstevel@tonic-gate nvpair_walk_step(mdb_walk_state_t *wsp)
73*0Sstevel@tonic-gate {
74*0Sstevel@tonic-gate 	int	status;
75*0Sstevel@tonic-gate 	nvpair_t *nvpair;
76*0Sstevel@tonic-gate 	i_nvp_t i_nvp, *tmp;
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
79*0Sstevel@tonic-gate 		return (WALK_DONE);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	if (mdb_vread(&i_nvp, sizeof (i_nvp), wsp->walk_addr) == -1) {
82*0Sstevel@tonic-gate 		mdb_warn("failed to read i_nvp at %p", wsp->walk_addr);
83*0Sstevel@tonic-gate 		return (WALK_ERR);
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	nvpair = &((i_nvp_t *)wsp->walk_addr)->nvi_nvp;
87*0Sstevel@tonic-gate 	status = wsp->walk_callback((uintptr_t)nvpair, NULL, wsp->walk_cbdata);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	tmp = i_nvp.nvi_next;
90*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)tmp;
91*0Sstevel@tonic-gate 	return (status);
92*0Sstevel@tonic-gate }
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  * nvpair dcmd
97*0Sstevel@tonic-gate  */
98*0Sstevel@tonic-gate typedef struct {
99*0Sstevel@tonic-gate 	data_type_t	type;
100*0Sstevel@tonic-gate 	int		elem_size;
101*0Sstevel@tonic-gate 	char		*type_name;
102*0Sstevel@tonic-gate } nvpair_info_t;
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate nvpair_info_t nvpair_info[] =  {
105*0Sstevel@tonic-gate 	{ DATA_TYPE_BOOLEAN,		1, "boolean" },
106*0Sstevel@tonic-gate 	{ DATA_TYPE_BOOLEAN_VALUE,	4, "boolean_value" },
107*0Sstevel@tonic-gate 	{ DATA_TYPE_BYTE,		1, "byte" },
108*0Sstevel@tonic-gate 	{ DATA_TYPE_INT8,		1, "int8" },
109*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT8,		1, "uint8" },
110*0Sstevel@tonic-gate 	{ DATA_TYPE_INT16,		2, "int16" },
111*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT16,		2, "uint16" },
112*0Sstevel@tonic-gate 	{ DATA_TYPE_INT32,		4, "int32" },
113*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT32,		4, "uint32" },
114*0Sstevel@tonic-gate 	{ DATA_TYPE_INT64,		8, "int64" },
115*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT64,		8, "uint64" },
116*0Sstevel@tonic-gate 	{ DATA_TYPE_STRING,		0, "string" },
117*0Sstevel@tonic-gate 	{ DATA_TYPE_NVLIST,		0, "nvpair_list" },
118*0Sstevel@tonic-gate 	{ DATA_TYPE_HRTIME,		8, "hrtime" },
119*0Sstevel@tonic-gate 	{ DATA_TYPE_BOOLEAN_ARRAY,	4, "boolean_array" },
120*0Sstevel@tonic-gate 	{ DATA_TYPE_BYTE_ARRAY,		1, "byte_array" },
121*0Sstevel@tonic-gate 	{ DATA_TYPE_INT8_ARRAY,		1, "int8_array" },
122*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT8_ARRAY,	1, "uint8_array" },
123*0Sstevel@tonic-gate 	{ DATA_TYPE_INT16_ARRAY,	2, "int16_array" },
124*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT16_ARRAY,	2, "uint16_array" },
125*0Sstevel@tonic-gate 	{ DATA_TYPE_INT32_ARRAY,	4, "int32_array" },
126*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT32_ARRAY,	4, "uint32_array" },
127*0Sstevel@tonic-gate 	{ DATA_TYPE_INT64_ARRAY, 	8, "int64_array" },
128*0Sstevel@tonic-gate 	{ DATA_TYPE_UINT64_ARRAY,	8, "uint64_array" },
129*0Sstevel@tonic-gate 	{ DATA_TYPE_STRING_ARRAY,	0, "string_array" },
130*0Sstevel@tonic-gate 	{ DATA_TYPE_NVLIST_ARRAY,	0, "nvpair list_array" }
131*0Sstevel@tonic-gate };
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate static void
134*0Sstevel@tonic-gate nvpair_print_value(char *data, int32_t elem_size, int32_t nelem,
135*0Sstevel@tonic-gate     data_type_t type)
136*0Sstevel@tonic-gate {
137*0Sstevel@tonic-gate 	int32_t i;
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	mdb_printf("value=");
140*0Sstevel@tonic-gate 	if (elem_size == 0) {
141*0Sstevel@tonic-gate 		char *p = data;
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 		/* print out all the strings */
144*0Sstevel@tonic-gate 		for (i = 0; i < nelem - 1; i++) {
145*0Sstevel@tonic-gate 			mdb_printf("'%s' + ", p);
146*0Sstevel@tonic-gate 			p += strlen(p) + 1;
147*0Sstevel@tonic-gate 		}
148*0Sstevel@tonic-gate 		mdb_printf("'%s'", p);
149*0Sstevel@tonic-gate 	} else if (type == DATA_TYPE_BOOLEAN_VALUE ||
150*0Sstevel@tonic-gate 	    type == DATA_TYPE_BOOLEAN_ARRAY) {
151*0Sstevel@tonic-gate 		/* LINTED - pointer alignment */
152*0Sstevel@tonic-gate 		boolean_t *p = (boolean_t *)data;
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 		for (i = 0; i < nelem; i++) {
155*0Sstevel@tonic-gate 			if (i > 0)
156*0Sstevel@tonic-gate 				mdb_printf(".");
157*0Sstevel@tonic-gate 			mdb_printf("%d", p[i]);
158*0Sstevel@tonic-gate 		}
159*0Sstevel@tonic-gate 	} else {
160*0Sstevel@tonic-gate 		unsigned char	*p = (unsigned char *)data;
161*0Sstevel@tonic-gate 		int		size = elem_size * nelem;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 		/*
164*0Sstevel@tonic-gate 		 * if elem_size != 0 then we are printing out an array
165*0Sstevel@tonic-gate 		 * where each element is of elem_size
166*0Sstevel@tonic-gate 		 */
167*0Sstevel@tonic-gate 		mdb_nhconvert(p, p, elem_size);
168*0Sstevel@tonic-gate 		mdb_printf("%02x", *p);
169*0Sstevel@tonic-gate 		for (i = 1; i < size; i++) {
170*0Sstevel@tonic-gate 			if ((i % elem_size) == 0) {
171*0Sstevel@tonic-gate 				mdb_nhconvert(&p[i], &p[i], elem_size);
172*0Sstevel@tonic-gate 				mdb_printf(".");
173*0Sstevel@tonic-gate 			}
174*0Sstevel@tonic-gate 			mdb_printf("%02x", p[i]);
175*0Sstevel@tonic-gate 		}
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate 	mdb_printf("\n");
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*ARGSUSED*/
181*0Sstevel@tonic-gate int
182*0Sstevel@tonic-gate nvpair_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate 	nvpair_t	nvpair_tmp, *nvpair;
185*0Sstevel@tonic-gate 	int32_t		i, size, nelem, elem_size = 0;
186*0Sstevel@tonic-gate 	char		*data = NULL, *data_end = NULL;
187*0Sstevel@tonic-gate 	char		*type_name = NULL;
188*0Sstevel@tonic-gate 	data_type_t	type = DATA_TYPE_UNKNOWN;
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
191*0Sstevel@tonic-gate 		return (DCMD_USAGE);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	/* read in the nvpair header so we can get the size */
194*0Sstevel@tonic-gate 	if (mdb_vread(&nvpair_tmp, sizeof (nvpair), addr) == -1) {
195*0Sstevel@tonic-gate 		mdb_warn("failed to read nvpair at %p", addr);
196*0Sstevel@tonic-gate 		return (DCMD_ERR);
197*0Sstevel@tonic-gate 	}
198*0Sstevel@tonic-gate 	size = NVP_SIZE(&nvpair_tmp);
199*0Sstevel@tonic-gate 	if (size == 0) {
200*0Sstevel@tonic-gate 		mdb_warn("nvpair of size zero at %p", addr);
201*0Sstevel@tonic-gate 		return (DCMD_OK);
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	/* read in the entire nvpair */
205*0Sstevel@tonic-gate 	nvpair = mdb_alloc(size, UM_SLEEP | UM_GC);
206*0Sstevel@tonic-gate 	if (mdb_vread(nvpair, size, addr) == -1) {
207*0Sstevel@tonic-gate 		mdb_warn("failed to read nvpair and data at %p", addr);
208*0Sstevel@tonic-gate 		return (DCMD_ERR);
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	/* lookup type decoding information for this nvpair */
212*0Sstevel@tonic-gate 	type = NVP_TYPE(nvpair);
213*0Sstevel@tonic-gate 	nelem = NVP_NELEM(nvpair);
214*0Sstevel@tonic-gate 	for (i = 0; i < NELEM(nvpair_info); i++) {
215*0Sstevel@tonic-gate 		if (nvpair_info[i].type == type) {
216*0Sstevel@tonic-gate 			elem_size = nvpair_info[i].elem_size;
217*0Sstevel@tonic-gate 			type_name = nvpair_info[i].type_name;
218*0Sstevel@tonic-gate 			break;
219*0Sstevel@tonic-gate 		}
220*0Sstevel@tonic-gate 	}
221*0Sstevel@tonic-gate 	/* print out the first line of nvpair info */
222*0Sstevel@tonic-gate 	mdb_printf("name='%s'", NVP_NAME(nvpair));
223*0Sstevel@tonic-gate 	if (type_name != NULL) {
224*0Sstevel@tonic-gate 		mdb_printf(" type=%s", type_name);
225*0Sstevel@tonic-gate 	} else {
226*0Sstevel@tonic-gate 		/* if the nvpair type is unknown we print the type number */
227*0Sstevel@tonic-gate 		mdb_printf(" type=0x%x", type);
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 	mdb_printf(" items=%d\n", nelem);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	/* if there is no data and the type is known then we're done */
232*0Sstevel@tonic-gate 	if ((nelem == 0) && (type_name != NULL))
233*0Sstevel@tonic-gate 		return (DCMD_OK);
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	/* get pointers to the data to print out */
236*0Sstevel@tonic-gate 	data = (char *)NVP_VALUE(nvpair);
237*0Sstevel@tonic-gate 	data_end = (char *)nvpair + NVP_SIZE(nvpair);
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	/*
240*0Sstevel@tonic-gate 	 * The value of the name-value pair for a single embedded
241*0Sstevel@tonic-gate 	 * list is the nvlist_t structure for the embedded list.
242*0Sstevel@tonic-gate 	 * So we print that address out (computed as an offset from
243*0Sstevel@tonic-gate 	 * the nvpair address we received as addr).
244*0Sstevel@tonic-gate 	 *
245*0Sstevel@tonic-gate 	 * The value of the name-value pair for an array of embedded
246*0Sstevel@tonic-gate 	 * lists is nelem pointers to nvlist_t structures followed
247*0Sstevel@tonic-gate 	 * by the structures themselves.  We display the list
248*0Sstevel@tonic-gate 	 * of pointers as the pair's value.
249*0Sstevel@tonic-gate 	 */
250*0Sstevel@tonic-gate 	if (type == DATA_TYPE_NVLIST) {
251*0Sstevel@tonic-gate 		char *p = (char *)addr + (data - (char *)nvpair);
252*0Sstevel@tonic-gate 		mdb_inc_indent(NVPAIR_VALUE_INDENT);
253*0Sstevel@tonic-gate 		mdb_printf("value=%p\n", p);
254*0Sstevel@tonic-gate 		mdb_dec_indent(NVPAIR_VALUE_INDENT);
255*0Sstevel@tonic-gate 		return (DCMD_OK);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	} else if (type == DATA_TYPE_NVLIST_ARRAY) {
258*0Sstevel@tonic-gate 		mdb_inc_indent(NVPAIR_VALUE_INDENT);
259*0Sstevel@tonic-gate 		mdb_printf("value=");
260*0Sstevel@tonic-gate 		for (i = 0; i < nelem; i++, data += sizeof (nvlist_t *)) {
261*0Sstevel@tonic-gate 			nvlist_t **nl = (nvlist_t **)(void *)data;
262*0Sstevel@tonic-gate 			mdb_printf("%c%p", " "[i == 0], *nl);
263*0Sstevel@tonic-gate 		}
264*0Sstevel@tonic-gate 		mdb_printf("\n");
265*0Sstevel@tonic-gate 		mdb_dec_indent(NVPAIR_VALUE_INDENT);
266*0Sstevel@tonic-gate 		return (DCMD_OK);
267*0Sstevel@tonic-gate 	}
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	/* if it's a string array, skip the index pointers */
270*0Sstevel@tonic-gate 	if (type == DATA_TYPE_STRING_ARRAY)
271*0Sstevel@tonic-gate 		data += (sizeof (int64_t) * nelem);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	/* if the type is unknown, treat the data as a byte array */
274*0Sstevel@tonic-gate 	if (type_name == NULL) {
275*0Sstevel@tonic-gate 		elem_size = 1;
276*0Sstevel@tonic-gate 		nelem = data_end - data;
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	/*
280*0Sstevel@tonic-gate 	 * if the type is of strings, make sure they are printable
281*0Sstevel@tonic-gate 	 * otherwise print them out as byte arrays
282*0Sstevel@tonic-gate 	 */
283*0Sstevel@tonic-gate 	if (elem_size == 0) {
284*0Sstevel@tonic-gate 		int32_t	count = 0;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 		i = 0;
287*0Sstevel@tonic-gate 		while ((&data[i] < data_end) && (count < nelem)) {
288*0Sstevel@tonic-gate 			if (data[i] == '\0')
289*0Sstevel@tonic-gate 				count++;
290*0Sstevel@tonic-gate 			else if (!isprint(data[i]))
291*0Sstevel@tonic-gate 				break;
292*0Sstevel@tonic-gate 			i++;
293*0Sstevel@tonic-gate 		}
294*0Sstevel@tonic-gate 		if (count != nelem) {
295*0Sstevel@tonic-gate 			/* there is unprintable data, output as byte array */
296*0Sstevel@tonic-gate 			elem_size = 1;
297*0Sstevel@tonic-gate 			nelem =  data_end - data;
298*0Sstevel@tonic-gate 		}
299*0Sstevel@tonic-gate 	}
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	mdb_inc_indent(NVPAIR_VALUE_INDENT);
302*0Sstevel@tonic-gate 	nvpair_print_value(data, elem_size, nelem, type);
303*0Sstevel@tonic-gate 	mdb_dec_indent(NVPAIR_VALUE_INDENT);
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	return (DCMD_OK);
306*0Sstevel@tonic-gate }
307