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