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