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