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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <mdb/mdb_modapi.h>
27 #include <sys/bitset.h>
28 
29 #include "bitset.h"		/* XXX work out ifdef in include file... */
30 
31 void
bitset_help(void)32 bitset_help(void)
33 {
34 	mdb_printf("Print the bitset at the address given\n");
35 }
36 
37 static void
bitset_free(bitset_t * bs)38 bitset_free(bitset_t *bs)
39 {
40 	if (bs == NULL)
41 		return;
42 	if (bs->bs_set && bs->bs_words)
43 		mdb_free(bs->bs_set, bs->bs_words * sizeof (ulong_t));
44 	mdb_free(bs, sizeof (*bs));
45 }
46 
47 static bitset_t *
bitset_get(uintptr_t bsaddr)48 bitset_get(uintptr_t bsaddr)
49 {
50 	bitset_t	*bs;
51 
52 	bs = mdb_zalloc(sizeof (*bs), UM_SLEEP);
53 	if (mdb_vread(bs, sizeof (*bs), bsaddr) == -1) {
54 		mdb_warn("couldn't read bitset 0x%p", bsaddr);
55 		bitset_free(bs);
56 		return (NULL);
57 	}
58 
59 	bsaddr = (uintptr_t)bs->bs_set;
60 	bs->bs_set = mdb_alloc(bs->bs_words * sizeof (ulong_t), UM_SLEEP);
61 	if (mdb_vread(bs->bs_set,
62 	    bs->bs_words * sizeof (ulong_t), bsaddr) == -1) {
63 		mdb_warn("couldn't read bitset bs_set 0x%p", bsaddr);
64 		bitset_free(bs);
65 		return (NULL);
66 	}
67 	return (bs);
68 
69 }
70 
71 static int
bitset_highbit(bitset_t * bs)72 bitset_highbit(bitset_t *bs)
73 {
74 	int	high;
75 	int	i;
76 
77 	if ((bs->bs_set == NULL) || (bs->bs_words == 0))
78 		return (-1);
79 
80 	/* move backwards through words */
81 	for (i = bs->bs_words; i >= 0; i--)
82 		if (bs->bs_set[i])
83 			break;
84 	if (i < 0)
85 		return (-1);
86 
87 	/* move backwards through bits */
88 	high = i << BT_ULSHIFT;
89 	for (i = BT_NBIPUL - 1; i; i--)
90 		if (BT_TEST(bs->bs_set, high + i))
91 			break;
92 	return (high + i + 1);
93 }
94 
95 static int
pow10(int exp)96 pow10(int exp)
97 {
98 	int	res;
99 
100 	for (res = 1; exp; exp--)
101 		res *= 10;
102 	return (res);
103 }
104 
105 static int
log10(int val)106 log10(int val)
107 {
108 	int	res = 0;
109 
110 	do {
111 		res++;
112 		val /= 10;
113 	} while (val);
114 	return (res);
115 }
116 
117 /*
118  * The following prints a bitset with a 'ruler' that look like this
119  *
120  *              11111111112222222222333333333344444444445555555555666666666677
121  *    012345678901234567890123456789012345678901234567890123456789012345678901
122  * xx:........................................................................
123  *                                11111111111111111111111111111111111111111111
124  *    777777778888888888999999999900000000001111111111222222222233333333334444
125  *    234567890123456789012345678901234567890123456789012345678901234567890123
126  *    ........................................................................
127  *    111111111111111111111111111111111111111111111111111111112222222222222222
128  *    444444555555555566666666667777777777888888888899999999990000000000111111
129  *    456789012345678901234567890123456789012345678901234567890123456789012345
130  *    ........................................................................
131  *    2222222222
132  *    1111222222
133  *    6789012345
134  *    ..........
135  *
136  * to identify individual bits that are set.
137  */
138 static void
bitset_print(bitset_t * bs,char * label,int width)139 bitset_print(bitset_t *bs, char *label, int width)
140 {
141 	int	val_start;
142 	int	val_max;
143 	int	label_width;
144 	int	ruler_width;
145 	int	v, vm, vi;
146 	int	nl, l;
147 	int	i;
148 	int	p;
149 	char	c;
150 
151 	val_start = 0;
152 	val_max = bitset_highbit(bs) + 1;
153 	if (val_max <= val_start) {
154 		mdb_printf("%s: empty-set", label);
155 		return;
156 	}
157 
158 	label_width = strlen(label) + 1;
159 	ruler_width = width - label_width;
160 
161 	for (v = val_start; v < val_max; v = vm) {
162 		if ((v + ruler_width) < val_max)
163 			vm = v + ruler_width;
164 		else
165 			vm = val_max;
166 
167 		nl = log10(vm) - 1;
168 		for (l = nl; l >= 0; l--) {
169 			p = pow10(l);
170 			for (i = 0; i < label_width; i++)
171 				mdb_printf(" ");
172 
173 			for (vi = v; vi < vm; vi++) {
174 				c = '0' + ((vi / p) % 10);
175 				if ((l == nl) && (c == '0'))
176 					c = ' ';
177 				mdb_printf("%c", c);
178 			}
179 
180 			mdb_printf("\n");
181 		}
182 
183 		if (v == val_start) {
184 			mdb_printf("%s:", label);
185 		} else {
186 			for (i = 0; i < label_width; i++)
187 				mdb_printf(" ");
188 		}
189 		for (vi = v; vi < vm; vi++) {
190 			if (BT_TEST(bs->bs_set, vi))
191 				mdb_printf("X");
192 			else
193 				mdb_printf(".");
194 		}
195 		mdb_printf("\n");
196 	}
197 }
198 
199 /*ARGSUSED*/
200 int
bitset(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)201 bitset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
202 {
203 	bitset_t	*bs;
204 
205 	bs = bitset_get(addr);
206 	if (bs == NULL)
207 		return (DCMD_ERR);
208 
209 	bitset_print(bs, "label", 80);
210 	bitset_free(bs);
211 	return (DCMD_OK);
212 }
213