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 32 bitset_help(void) 33 { 34 mdb_printf("Print the bitset at the address given\n"); 35 } 36 37 static void 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 * 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 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 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 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 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 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