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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr3.2H */ 27 28 /* 29 * Dump STREAMS module. Could be used anywhere on a stream to 30 * print all message headers and data on to the console. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/stream.h> 37 #include <sys/stropts.h> 38 #include <sys/errno.h> 39 #include <sys/cmn_err.h> 40 #include <sys/ddi.h> 41 #include <sys/strsun.h> 42 43 #include <sys/conf.h> 44 #include <sys/modctl.h> 45 46 static char hdr[100]; /* current message header */ 47 static char hdrpad[100]; /* pad of same length as hdr[] */ 48 49 /* 50 * Raw buffer dumping routine. Displays the contents of the first message in 51 * message chain `mp', using the "traditional" dump format. 52 * 53 * For instance, "Hello STREAMS, panicked lately?" would be displayed as: 54 * 55 * RD 30001dbb240 M_DATA 48656C6C 6F205354 5245414D 532C2070 Hello STREAMS, p 56 * 616E6963 6B656420 6C617465 6C793F anicked lately? 57 * 58 * If the character being displayed is not printable, a '.' is shown. 59 */ 60 61 #define DEDUMP_HEXPERBLK 4 62 #define DEDUMP_HEXLEN (sizeof ("11223344") * 4) 63 #define DEDUMP_ASCLEN (sizeof ("0123456789ABCDEF") - 1) 64 65 static void 66 dedump_raw(mblk_t *mp) 67 { 68 char hex[DEDUMP_HEXLEN + 1], asc[DEDUMP_ASCLEN + 1]; 69 int hexi = 0, asci = 0, i = 0; 70 uchar_t c; 71 char *hdrp = hdr; 72 73 hex[DEDUMP_HEXLEN] = '\0'; 74 75 for (;;) { 76 if (i == MBLKL(mp) || (i != 0 && (i % DEDUMP_ASCLEN) == 0)) { 77 /* 78 * We're either out of data or we've filled a complete 79 * line. In either case, print out what we've got -- 80 * but first NUL-terminate asc[] and pad out hex[] 81 * with spaces. 82 */ 83 asc[asci] = '\0'; 84 (void) memset(hex + hexi, ' ', DEDUMP_HEXLEN - hexi); 85 (void) printf("%s %s %s\n", hdrp, hex, asc); 86 87 /* 88 * If we're out of data, bail. Otherwise, reset asci 89 * and hexi for another lap around. Also, set hdrp to 90 * the pad since we only want to show the header once. 91 */ 92 if (i == MBLKL(mp)) 93 break; 94 asci = 0; 95 hexi = 0; 96 hdrp = hdrpad; 97 } 98 99 c = mp->b_rptr[i++]; 100 101 hexi += snprintf(hex + hexi, 3, "%02X", c); 102 if ((i % DEDUMP_HEXPERBLK) == 0) 103 hex[hexi++] = ' '; 104 asc[asci++] = (c >= 32 && c <= 126) ? c : '.'; 105 } 106 } 107 108 static void 109 dedump_char(mblk_t *mp) 110 { 111 (void) printf("%s 0x%x\n", hdr, *(uchar_t *)mp->b_rptr); 112 } 113 114 static void 115 dedump_int(mblk_t *mp) 116 { 117 (void) printf("%s %d\n", hdr, *(int *)mp->b_rptr); 118 } 119 120 static void 121 dedump_ssize(mblk_t *mp) 122 { 123 (void) printf("%s %ld\n", hdr, *(ssize_t *)mp->b_rptr); 124 } 125 126 static void 127 dedump_cmdblk(mblk_t *mp) 128 { 129 struct cmdblk *cbp = (struct cmdblk *)mp->b_rptr; 130 131 (void) printf("%s cmd %x cred %p len %u error %d\n", hdr, cbp->cb_cmd, 132 (void *)cbp->cb_cr, cbp->cb_len, cbp->cb_error); 133 } 134 135 static void 136 dedump_iocblk(mblk_t *mp) 137 { 138 struct iocblk *ic = (struct iocblk *)mp->b_rptr; 139 140 (void) printf("%s cmd %x cred %p id %u flag %x count %ld rval %d " 141 "err %d\n", hdr, ic->ioc_cmd, (void *)ic->ioc_cr, ic->ioc_id, 142 ic->ioc_flag, ic->ioc_count, ic->ioc_rval, ic->ioc_error); 143 } 144 145 static void 146 dedump_stroptions(mblk_t *mp) 147 { 148 struct stroptions *so = (struct stroptions *)mp->b_rptr; 149 150 (void) printf("%s flag %x readopt %d wroff %u\n", hdr, 151 so->so_flags, so->so_readopt, so->so_wroff); 152 153 (void) printf("%s minpsz %ld maxpsz %ld hiwat %lu lowat %lu\n", hdrpad, 154 so->so_minpsz, so->so_maxpsz, so->so_hiwat, so->so_lowat); 155 156 (void) printf("%s band %u erropt %u maxblk %ld copyopt %u\n", hdrpad, 157 so->so_band, so->so_erropt, so->so_maxblk, so->so_copyopt); 158 } 159 160 static void 161 dedump_copyreq(mblk_t *mp) 162 { 163 struct copyreq *cq = (struct copyreq *)mp->b_rptr; 164 165 (void) printf("%s cmd %x cred %p id %u flag %x priv %p addr %p size " 166 "%lu\n", hdr, cq->cq_cmd, (void *)cq->cq_cr, cq->cq_id, cq->cq_flag, 167 (void *)cq->cq_private, (void *)cq->cq_addr, cq->cq_size); 168 } 169 170 static void 171 dedump_copyresp(mblk_t *mp) 172 { 173 struct copyresp *cp = (struct copyresp *)mp->b_rptr; 174 175 (void) printf("%s cmd %x cred %p id %u flag %x priv %p rval %p\n", hdr, 176 cp->cp_cmd, (void *)cp->cp_cr, cp->cp_id, cp->cp_flag, 177 (void *)cp->cp_private, (void *)cp->cp_rval); 178 } 179 180 typedef struct msgfmt { 181 uchar_t m_type; 182 char m_desc[15]; 183 void (*m_print)(mblk_t *); 184 } msgfmt_t; 185 186 static msgfmt_t msgfmt[256] = { 187 { M_DATA, "M_DATA ", dedump_raw }, 188 { M_PROTO, "M_PROTO ", dedump_raw }, 189 { M_BREAK, "M_BREAK ", dedump_raw }, 190 { M_PASSFP, "M_PASSFP ", dedump_raw }, 191 { M_EVENT, "M_EVENT ", dedump_raw }, 192 { M_SIG, "M_SIG ", dedump_char }, 193 { M_DELAY, "M_DELAY ", dedump_int }, 194 { M_CTL, "M_CTL ", dedump_raw }, 195 { M_IOCTL, "M_IOCTL ", dedump_iocblk }, 196 { M_SETOPTS, "M_SETOPTS ", dedump_stroptions }, 197 { M_RSE, "M_RSE ", dedump_raw }, 198 { M_IOCACK, "M_IOCACK ", dedump_iocblk }, 199 { M_IOCNAK, "M_IOCNAK ", dedump_iocblk }, 200 { M_PCPROTO, "M_PCPROTO ", dedump_raw }, 201 { M_PCSIG, "M_PCSIG ", dedump_char }, 202 { M_READ, "M_READ ", dedump_ssize }, 203 { M_FLUSH, "M_FLUSH ", dedump_char }, 204 { M_STOP, "M_STOP ", dedump_raw }, 205 { M_START, "M_START ", dedump_raw }, 206 { M_HANGUP, "M_HANGUP ", dedump_raw }, 207 { M_ERROR, "M_ERROR ", dedump_char }, 208 { M_COPYIN, "M_COPYIN ", dedump_copyreq }, 209 { M_COPYOUT, "M_COPYOUT ", dedump_copyreq }, 210 { M_IOCDATA, "M_IOCDATA ", dedump_copyresp }, 211 { M_PCRSE, "M_PCRSE ", dedump_raw }, 212 { M_STOPI, "M_STOPI ", dedump_raw }, 213 { M_STARTI, "M_STARTI ", dedump_raw }, 214 { M_PCEVENT, "M_PCEVENT ", dedump_raw }, 215 { M_UNHANGUP, "M_UNHANGUP", dedump_raw }, 216 { M_CMD, "M_CMD ", dedump_cmdblk }, 217 }; 218 219 /*ARGSUSED1*/ 220 static int 221 dedumpopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) 222 { 223 if (!sflag) 224 return (ENXIO); 225 226 if (q->q_ptr) 227 return (0); /* already attached */ 228 229 qprocson(q); 230 return (0); 231 } 232 233 /*ARGSUSED1*/ 234 static int 235 dedumpclose(queue_t *q, int flag, cred_t *crp) 236 { 237 qprocsoff(q); 238 return (0); 239 } 240 241 /* 242 * Common put procedure for upstream and downstream. 243 */ 244 static int 245 dedumpput(queue_t *q, mblk_t *mp) 246 { 247 unsigned char type = DB_TYPE(mp); 248 ssize_t hdrlen; 249 250 hdrlen = snprintf(hdr, sizeof (hdr), "%s %p %10s ", 251 (q->q_flag & QREADR) ? "RD" : "WR", (void *)q, msgfmt[type].m_desc); 252 253 hdrpad[hdrlen] = '\0'; 254 msgfmt[type].m_print(mp); 255 hdrpad[hdrlen] = ' '; 256 257 putnext(q, mp); 258 return (0); 259 } 260 261 struct module_info dedump_minfo = { 262 0xaaa, "dedump", 0, INFPSZ, 0, 0 263 }; 264 265 struct qinit dedumprinit = { 266 dedumpput, NULL, dedumpopen, dedumpclose, NULL, &dedump_minfo, NULL 267 }; 268 269 struct qinit dedumpwinit = { 270 dedumpput, NULL, NULL, NULL, NULL, &dedump_minfo, NULL 271 }; 272 273 struct streamtab dedumpinfo = { 274 &dedumprinit, &dedumpwinit, NULL, NULL, 275 }; 276 277 static struct fmodsw fsw = { 278 "dedump", 279 &dedumpinfo, 280 D_MP | D_MTPERMOD /* just to serialize printfs */ 281 }; 282 283 static struct modlstrmod modlstrmod = { 284 &mod_strmodops, "dump streams module", &fsw 285 }; 286 287 static struct modlinkage modlinkage = { 288 MODREV_1, &modlstrmod, NULL 289 }; 290 291 int 292 _init(void) 293 { 294 int i; 295 msgfmt_t mf; 296 297 /* 298 * Sort msgfmt[] so that msgfmt[n] describes message type n. 299 */ 300 for (i = 255; i != 0; i--) { 301 mf = msgfmt[i]; 302 msgfmt[i].m_type = i; 303 (void) sprintf(msgfmt[i].m_desc, "M_BOGUS_0x%x", i); 304 msgfmt[i].m_print = dedump_raw; 305 if (mf.m_desc[0] != 0) 306 msgfmt[mf.m_type] = mf; 307 } 308 309 /* 310 * Fill hdrpad[] with as many spaces as will fit. 311 */ 312 (void) memset(hdrpad, ' ', sizeof (hdrpad) - 1); 313 hdrpad[sizeof (hdrpad) - 1] = '\0'; 314 315 return (mod_install(&modlinkage)); 316 } 317 318 int 319 _fini(void) 320 { 321 return (mod_remove(&modlinkage)); 322 } 323 324 int 325 _info(struct modinfo *modinfop) 326 { 327 return (mod_info(&modlinkage, modinfop)); 328 }