xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/streams.c (revision 1f5207b7604fb44407eb4342aff613f7c4508508)
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 <mdb/mdb_ks.h>
28 
29 #include <ctype.h>
30 #include <sys/types.h>
31 #include <sys/strsubr.h>
32 #include <sys/stream.h>
33 #include <sys/modctl.h>
34 #include <sys/strft.h>
35 #include <sys/strsun.h>
36 #include <sys/sysmacros.h>
37 
38 #include "streams.h"
39 
40 typedef struct str_flags {
41 	uint_t strf_flag;
42 	const char *strf_name;
43 	const char *strf_descr;
44 } strflags_t;
45 
46 typedef struct str_types {
47 	const char *strt_name;
48 	int strt_value;
49 	const char *strt_descr;
50 } strtypes_t;
51 
52 typedef struct ftblk_data {
53 	ftblk_t ft_data;	/* Copy of ftblk */
54 	int 	ft_ix;		/* Index in event list */
55 	boolean_t ft_in_evlist;	/* Iterating through evlist */
56 } ftblkdata_t;
57 
58 typedef void qprint_func(queue_t *, queue_t *);
59 typedef void sdprint_func(stdata_t *, stdata_t *);
60 
61 #define	SF(flag)	flag, #flag
62 
63 /*
64  * Queue flags
65  */
66 static const strflags_t qf[] = {
67 	{ SF(QENAB), 		"Queue is already enabled to run"	},
68 	{ SF(QWANTR),		"Someone wants to read Q"		},
69 	{ SF(QWANTW),		"Someone wants to write Q"		},
70 	{ SF(QFULL),		"Q is considered full"			},
71 	{ SF(QREADR),		"This is the reader (first) Q"		},
72 	{ SF(QUSE),		"This queue in use (allocation)"	},
73 	{ SF(QNOENB),		"Don't enable Q via putq"		},
74 	{ SF(QWANTRMQSYNC),	"Want to remove sync stream Q"		},
75 	{ SF(QBACK),		"queue has been back-enabled"		},
76 	{ SF(0x00000200),	"unused (was QHLIST)"			},
77 	{ SF(0x00000400),	"unused (was QUNSAFE)"			},
78 	{ SF(QPAIR),		"per queue-pair syncq"			},
79 	{ SF(QPERQ),		"per queue-instance syncq"		},
80 	{ SF(QPERMOD),		"per module syncq"			},
81 	{ SF(QMTSAFE),		"stream module is MT-safe"		},
82 	{ SF(QMTOUTPERIM),	"Has outer perimeter"			},
83 	{ SF(QINSERVICE),	"service routine executing"		},
84 	{ SF(QWCLOSE),		"will not be enabled"			},
85 	{ SF(QEND),		"last queue in stream"			},
86 	{ SF(QWANTWSYNC),	"Streamhead wants to write Q" 		},
87 	{ SF(QSYNCSTR),		"Q supports Synchronous STREAMS"	},
88 	{ SF(QISDRV),		"the Queue is attached to a driver"	},
89 	{ SF(0x00400000),	"unused (was QHOT)"			},
90 	{ SF(0x00800000),	"unused (was QNEXTHOT)"			},
91 	{ SF(0x01000000),	"unused (was _QNEXTLESS)"		},
92 	{ SF(0x02000000),	"unused"				},
93 	{ SF(_QINSERTING),	"module is inserted with _I_INSERT"	},
94 	{ SF(_QREMOVING)	"module is removed with _I_REMOVE"	},
95 	{ SF(_QASSOCIATED),	"queue is associated with a device"	},
96 	{ 0, NULL,		NULL					}
97 };
98 
99 /*
100  * Syncq flags
101  */
102 static const struct str_flags sqf[] = {
103 	{ SF(SQ_EXCL),		"Exclusive access to inner perimeter"	},
104 	{ SF(SQ_BLOCKED),	"qprocsoff in progress"			},
105 	{ SF(SQ_FROZEN),	"freezestr in progress"			},
106 	{ SF(SQ_WRITER),	"qwriter(OUTER) pending or running"	},
107 	{ SF(SQ_MESSAGES),	"There are messages on syncq"		},
108 	{ SF(SQ_WANTWAKEUP)	"Thread waiting on sq_wait"		},
109 	{ SF(SQ_WANTEXWAKEUP),	"Thread waiting on sq_exwait"		},
110 	{ SF(SQ_EVENTS),	"There are events on syncq"		},
111 	{ 0, NULL,		NULL					}
112 };
113 
114 /*
115  * Syncq types
116  */
117 static const struct str_flags sqt[] = {
118 	{ SF(SQ_CIPUT),		"Concurrent inner put procedure"	},
119 	{ SF(SQ_CISVC),		"Concurrent inner svc procedure"	},
120 	{ SF(SQ_CIOC),		"Concurrent inner open/close"		},
121 	{ SF(SQ_CICB),		"Concurrent inner callback"		},
122 	{ SF(SQ_COPUT),		"Concurrent outer put procedure"	},
123 	{ SF(SQ_COSVC),		"Concurrent outer svc procedure"	},
124 	{ SF(SQ_COOC),		"Concurrent outer open/close"		},
125 	{ SF(SQ_COCB),		"Concurrent outer callback"		},
126 	{ 0, NULL,		NULL					}
127 };
128 
129 /*
130  * Stdata flags
131  */
132 static const struct str_flags stdf[] = {
133 	{ SF(IOCWAIT),		"someone is doing an ioctl"		},
134 	{ SF(RSLEEP),		"someone wants to read/recv msg"	},
135 	{ SF(WSLEEP),		"someone wants to write"		},
136 	{ SF(STRPRI),		"an M_PCPROTO is at stream head"	},
137 	{ SF(STRHUP),		"device has vanished"			},
138 	{ SF(STWOPEN),		"waiting for 1st open"			},
139 	{ SF(STPLEX),		"stream is being multiplexed"		},
140 	{ SF(STRISTTY),		"stream is a terminal"			},
141 	{ SF(STRGETINPROG),	"(k)strgetmsg is running"		},
142 	{ SF(IOCWAITNE),	"STR_NOERROR ioctl running"		},
143 	{ SF(STRDERR),		"fatal read error from M_ERROR"		},
144 	{ SF(STWRERR),		"fatal write error from M_ERROR"	},
145 	{ SF(STRDERRNONPERSIST), "nonpersistent read errors"		},
146 	{ SF(STWRERRNONPERSIST), "nonpersistent write errors"		},
147 	{ SF(STRCLOSE),		"wait for a close to complete"		},
148 	{ SF(SNDMREAD),		"used for read notification"		},
149 	{ SF(OLDNDELAY),	"use old NDELAY TTY semantics"		},
150 	{ SF(0x00020000),	"unused"				},
151 	{ SF(0x00040000),	"unused"				},
152 	{ SF(STRTOSTOP),	"block background writes"		},
153 	{ SF(STRCMDWAIT),	"someone is doing an _I_CMD"		},
154 	{ SF(0x00200000),	"unused"				},
155 	{ SF(STRMOUNT),		"stream is mounted"			},
156 	{ SF(STRNOTATMARK),	"Not at mark (when empty read q)"	},
157 	{ SF(STRDELIM),		"generate delimited messages"		},
158 	{ SF(STRATMARK),	"at mark (due to MSGMARKNEXT)"		},
159 	{ SF(STZCNOTIFY),	"wait for zerocopy mblk to be acked"	},
160 	{ SF(STRPLUMB),		"stream plumbing changes in progress"	},
161 	{ SF(STREOF),  		"End-of-file indication"		},
162 	{ SF(STREOPENFAIL),	"re-open has failed"			},
163 	{ SF(STRMATE),		"this stream is a mate"			},
164 	{ SF(STRHASLINKS),	"there are I_LINKs under this stream"	},
165 	{ 0, NULL,		NULL					}
166 };
167 
168 static const struct str_flags mbf[] = {
169 	{ SF(MSGMARK), 		"last byte of message is marked"	},
170 	{ SF(MSGNOLOOP),	"don't loop message to write side"	},
171 	{ SF(MSGDELIM),		"message is delimited"			},
172 	{ SF(0x08),		"unused"				},
173 	{ SF(MSGMARKNEXT), 	"Private: b_next's first byte marked"	},
174 	{ SF(MSGNOTMARKNEXT),	"Private: ... not marked"		},
175 	{ 0, NULL,		NULL					}
176 };
177 
178 #define	M_DATA_T 0xff
179 
180 static const strtypes_t mbt[] = {
181 	{ "M_DATA",	M_DATA_T,	"regular data"			},
182 	{ "M_PROTO",	M_PROTO,	"protocol control"		},
183 	{ "M_MULTIDATA", M_MULTIDATA,	"multidata"			},
184 	{ "M_BREAK",	M_BREAK,	"line break"			},
185 	{ "M_PASSFP",	M_PASSFP,	"pass file pointer"		},
186 	{ "M_EVENT",	M_EVENT,	"Obsoleted: do not use"		},
187 	{ "M_SIG",	M_SIG,		"generate process signal"	},
188 	{ "M_DELAY",	M_DELAY,	"real-time xmit delay"		},
189 	{ "M_CTL",	M_CTL,		"device-specific control message" },
190 	{ "M_IOCTL",	M_IOCTL,	"ioctl; set/get params"		},
191 	{ "M_SETOPTS",	M_SETOPTS,	"set stream head options"	},
192 	{ "M_RSE",	M_RSE,		"reserved for RSE use only"	},
193 	{ "M_IOCACK",	M_IOCACK,	"acknowledge ioctl"		},
194 	{ "M_IOCNAK",	M_IOCNAK,	"negative ioctl acknowledge"	},
195 	{ "M_PCPROTO",	M_PCPROTO,	"priority proto message"	},
196 	{ "M_PCSIG",	M_PCSIG,	"generate process signal"	},
197 	{ "M_READ",	M_READ,		"generate read notification"	},
198 	{ "M_FLUSH",	M_FLUSH,	"flush your queues"		},
199 	{ "M_STOP",	M_STOP,		"stop transmission immediately" },
200 	{ "M_START",	M_START,	"restart transmission after stop" },
201 	{ "M_HANGUP",	M_HANGUP,	"line disconnect"		},
202 	{ "M_ERROR",	M_ERROR,	"send error to stream head"	},
203 	{ "M_COPYIN",	M_COPYIN,	"request to copyin data"	},
204 	{ "M_COPYOUT",	M_COPYOUT,	"request to copyout data"	},
205 	{ "M_IOCDATA",	M_IOCDATA,	"response to M_COPYIN and M_COPYOUT" },
206 	{ "M_PCRSE",	M_PCRSE,	"reserved for RSE use only"	},
207 	{ "M_STOPI",	M_STOPI,	"stop reception immediately"	},
208 	{ "M_STARTI",	M_STARTI,	"restart reception after stop"	},
209 	{ "M_PCEVENT",	M_PCEVENT,	"Obsoleted: do not use"		},
210 	{ "M_UNHANGUP",	M_UNHANGUP,	"line reconnect"		},
211 	{ "M_CMD",	M_CMD,		"out-of-band ioctl command"	},
212 	{ NULL,		0,		NULL 				}
213 };
214 
215 /* Allocation flow trace events, starting from 0 */
216 static const char *ftev_alloc[] = {
217 /* 0 */	"allocb",
218 /* 1 */	"esballoc",
219 /* 2 */	"desballoc",
220 /* 3 */	"esballoca",
221 /* 4 */	"desballoca",
222 /* 5 */	"allocbig",
223 /* 6 */	"allocbw",
224 /* 7 */	"bcallocb",
225 /* 8 */	"freeb",
226 /* 9 */	"dupb",
227 /* A */	"copyb",
228 };
229 
230 #define	FTEV_PROC_START FTEV_PUT
231 
232 /* Procedures recorded by flow tracing, starting from 0x100 */
233 static const char *ftev_proc[] = {
234 /* 100 */	"put",
235 /* 101 */	"0x101",
236 /* 102 */	"0x102",
237 /* 103 */	"0x103",
238 /* 104 */	"0x104",
239 /* 105 */	"putq",
240 /* 106 */	"getq",
241 /* 107 */	"rmvq",
242 /* 108 */	"insq",
243 /* 109 */	"putbq",
244 /* 10A */	"flushq",
245 /* 10B */	"0x10b",
246 /* 10C */ 	"0x10c",
247 /* 10D */	"putnext",
248 /* 10E */	"rwnext",
249 };
250 
251 static const char *db_control_types[] = {
252 /* 00 */	"data",
253 /* 01 */	"proto",
254 /* 02 */	"multidata",
255 /* 03 */	"0x03",
256 /* 04 */	"0x04",
257 /* 05 */	"0x05",
258 /* 06 */	"0x06",
259 /* 07 */	"0x07",
260 /* 08 */	"break",
261 /* 09 */	"passfp",
262 /* 0a */	"event",
263 /* 0b */	"sig",
264 /* 0c */	"delay",
265 /* 0d */	"ctl",
266 /* 0e */	"ioctl",
267 /* 0f */	"unused",
268 /* 10 */	"setopts",
269 /* 11 */	"rse",
270 };
271 
272 static const char *db_control_hipri_types[] = {
273 /* 81 */	"iocack",
274 /* 82 */	"iocnak",
275 /* 83 */	"pcproto",
276 /* 84 */	"pcsig",
277 /* 85 */	"read",
278 /* 86 */	"flush",
279 /* 87 */	"stop",
280 /* 88 */	"start",
281 /* 89 */	"hangup",
282 /* 8a */	"error",
283 /* 8b */	"copyin",
284 /* 8c */	"copyout",
285 /* 8d */	"iocdata",
286 /* 8e */	"pcrse",
287 /* 8f */	"stopi",
288 /* 90 */	"starti",
289 /* 91 */	"pcevent",
290 /* 92 */	"unhangup",
291 /* 93 */	"cmd",
292 };
293 
294 #define	A_SIZE(a) (sizeof (a) / sizeof (a[0]))
295 
296 static void ft_printevent(ushort_t);
297 
298 static int
299 streams_parse_flag(const strflags_t ftable[], const char *arg, uint32_t *flag)
300 {
301 	int i;
302 
303 	for (i = 0; ftable[i].strf_name != NULL; i++) {
304 		if (strcasecmp(arg, ftable[i].strf_name) == 0) {
305 			*flag |= (1 << i);
306 			return (0);
307 		}
308 	}
309 
310 	return (-1);
311 }
312 
313 static void
314 streams_flag_usage(const strflags_t ftable[])
315 {
316 	int i;
317 
318 	for (i = 0; ftable[i].strf_name != NULL; i++)
319 		mdb_printf("%-14s %s\n",
320 		    ftable[i].strf_name, ftable[i].strf_descr);
321 }
322 
323 static int
324 streams_parse_type(const strtypes_t ftable[], const char *arg, uint32_t *flag)
325 {
326 	int i;
327 
328 	for (i = 0; ftable[i].strt_name != NULL; i++) {
329 		if (strcasecmp(arg, ftable[i].strt_name) == 0) {
330 			*flag = ftable[i].strt_value;
331 			return (0);
332 		}
333 	}
334 
335 	return (-1);
336 }
337 
338 static void
339 streams_type_usage(const strtypes_t ftable[])
340 {
341 	int i;
342 
343 	for (i = 0; ftable[i].strt_name != NULL; i++)
344 		mdb_printf("%-12s %s\n",
345 		    ftable[i].strt_name, ftable[i].strt_descr);
346 }
347 
348 int
349 queue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
350 {
351 	const int QUEUE_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
352 
353 	char name[MODMAXNAMELEN];
354 	int nblks = 0;
355 	uintptr_t maddr;
356 	mblk_t mblk;
357 	queue_t q;
358 
359 	const char *mod = NULL, *flag = NULL, *not_flag = NULL;
360 	uint_t quiet = FALSE;
361 	uint_t verbose = FALSE;
362 	uint32_t mask = 0, not_mask = 0;
363 	uintptr_t syncq = 0;
364 
365 	if (!(flags & DCMD_ADDRSPEC)) {
366 		if (mdb_walk_dcmd("genunix`queue_cache", "genunix`queue",
367 		    argc, argv) == -1) {
368 			mdb_warn("failed to walk queue cache");
369 			return (DCMD_ERR);
370 		}
371 		return (DCMD_OK);
372 	}
373 
374 	if (flags & DCMD_PIPE_OUT)
375 		quiet = TRUE;
376 
377 	if (mdb_getopts(argc, argv,
378 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
379 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
380 	    'm', MDB_OPT_STR, &mod,
381 	    'f', MDB_OPT_STR, &flag,
382 	    'F', MDB_OPT_STR, &not_flag,
383 	    's', MDB_OPT_UINTPTR, &syncq,
384 	    NULL) != argc)
385 		return (DCMD_USAGE);
386 
387 	/*
388 	 * If any of the filtering flags is specified, don't print anything
389 	 * except the matching pointer.
390 	 */
391 	if (flag != NULL || not_flag != NULL || mod != NULL || syncq != NULL)
392 		quiet = TRUE;
393 
394 	if (DCMD_HDRSPEC(flags) && !quiet) {
395 		mdb_printf("%?s %-13s %6s %4s\n",
396 		    "ADDR", "MODULE", "FLAGS", "NBLK");
397 	}
398 
399 	if (flag != NULL && streams_parse_flag(qf, flag, &mask) == -1) {
400 		mdb_warn("unrecognized queue flag '%s'\n", flag);
401 		streams_flag_usage(qf);
402 		return (DCMD_USAGE);
403 	}
404 
405 	if (not_flag != NULL &&
406 	    streams_parse_flag(qf, not_flag, &not_mask) == -1) {
407 		mdb_warn("unrecognized queue flag '%s'\n", flag);
408 		streams_flag_usage(qf);
409 		return (DCMD_USAGE);
410 	}
411 
412 	if (mdb_vread(&q, sizeof (q), addr) == -1) {
413 		mdb_warn("couldn't read queue at %p", addr);
414 		return (DCMD_ERR);
415 	}
416 
417 	for (maddr = (uintptr_t)q.q_first; maddr != NULL; nblks++) {
418 		if (mdb_vread(&mblk, sizeof (mblk), maddr) == -1) {
419 			mdb_warn("couldn't read mblk %p for queue %p",
420 			    maddr, addr);
421 			break;
422 		}
423 		maddr = (uintptr_t)mblk.b_next;
424 	}
425 
426 	(void) mdb_qname(&q, name, sizeof (name));
427 
428 	/*
429 	 * If queue doesn't pass filtering criteria, don't print anything and
430 	 * just return.
431 	 */
432 
433 	if (mod != NULL && strcmp(mod, name) != 0)
434 		return (DCMD_OK);
435 
436 	if (mask != 0 && !(q.q_flag & mask))
437 		return (DCMD_OK);
438 
439 	if (not_mask != 0 && (q.q_flag & not_mask))
440 		return (DCMD_OK);
441 
442 	if (syncq != 0 && q.q_syncq != (syncq_t *)syncq)
443 		return (DCMD_OK);
444 
445 	/*
446 	 * Options are specified for filtering, so If any option is specified on
447 	 * the command line, just print address and exit.
448 	 */
449 	if (quiet) {
450 		mdb_printf("%0?p\n", addr);
451 		return (DCMD_OK);
452 	}
453 
454 	mdb_printf("%0?p %-13s %06x %4d %0?p\n",
455 	    addr, name, q.q_flag, nblks, q.q_first);
456 
457 	if (verbose) {
458 		int i, arm = 0;
459 
460 		for (i = 0; qf[i].strf_name != NULL; i++) {
461 			if (!(q.q_flag & (1 << i)))
462 				continue;
463 			if (!arm) {
464 				mdb_printf("%*s|\n%*s+-->  ",
465 				    QUEUE_FLGDELT, "", QUEUE_FLGDELT, "");
466 				arm = 1;
467 			} else
468 				mdb_printf("%*s      ", QUEUE_FLGDELT, "");
469 
470 			mdb_printf("%-12s %s\n",
471 			    qf[i].strf_name, qf[i].strf_descr);
472 		}
473 	}
474 
475 	return (DCMD_OK);
476 }
477 
478 int
479 syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
480 {
481 	const int SYNC_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 1);
482 	const int SYNC_TYPDELT = (int)(sizeof (uintptr_t) * 2 + 5);
483 	syncq_t sq;
484 
485 	const char *flag = NULL, *not_flag = NULL;
486 	const char *typ = NULL, *not_typ = NULL;
487 	uint_t verbose = FALSE;
488 	uint_t quiet = FALSE;
489 	uint32_t mask = 0, not_mask = 0;
490 	uint32_t tmask = 0, not_tmask = 0;
491 	uint8_t sqtype = 0;
492 
493 	if (!(flags & DCMD_ADDRSPEC)) {
494 		if (mdb_walk_dcmd("genunix`syncq_cache", "genunix`syncq",
495 		    argc, argv) == -1) {
496 			mdb_warn("failed to walk syncq cache");
497 			return (DCMD_ERR);
498 		}
499 		return (DCMD_OK);
500 	}
501 
502 	if (flags & DCMD_PIPE_OUT)
503 		quiet = TRUE;
504 
505 	if (mdb_getopts(argc, argv,
506 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
507 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
508 	    'f', MDB_OPT_STR, &flag,
509 	    'F', MDB_OPT_STR, &not_flag,
510 	    't', MDB_OPT_STR, &typ,
511 	    'T', MDB_OPT_STR, &not_typ,
512 	    NULL) != argc)
513 		return (DCMD_USAGE);
514 
515 	/*
516 	 * If any of the filtering flags is specified, don't print anything
517 	 * except the matching pointer.
518 	 */
519 	if (flag != NULL || not_flag != NULL || typ != NULL || not_typ != NULL)
520 		quiet = TRUE;
521 
522 	if (DCMD_HDRSPEC(flags) && !quiet) {
523 		mdb_printf("%?s %s %s %s %s %?s %s %s\n",
524 		    "ADDR", "FLG", "TYP", "CNT", "NQS", "OUTER", "SF", "PRI");
525 	}
526 
527 	if (flag != NULL && streams_parse_flag(sqf, flag, &mask) == -1) {
528 		mdb_warn("unrecognized syncq flag '%s'\n", flag);
529 		streams_flag_usage(sqf);
530 		return (DCMD_USAGE);
531 	}
532 
533 	if (typ != NULL && streams_parse_flag(sqt, typ, &tmask) == -1) {
534 		mdb_warn("unrecognized syncq type '%s'\n", typ);
535 		streams_flag_usage(sqt);
536 		return (DCMD_USAGE);
537 	}
538 
539 	if (not_flag != NULL && streams_parse_flag(sqf, not_flag, &not_mask)
540 	    == -1) {
541 		mdb_warn("unrecognized syncq flag '%s'\n", not_flag);
542 		streams_flag_usage(sqf);
543 		return (DCMD_USAGE);
544 	}
545 
546 	if (not_typ != NULL && streams_parse_flag(sqt, not_typ, &not_tmask)
547 	    == -1) {
548 		mdb_warn("unrecognized syncq type '%s'\n", not_typ);
549 		streams_flag_usage(sqt);
550 		return (DCMD_USAGE);
551 	}
552 
553 	if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
554 		mdb_warn("couldn't read syncq at %p", addr);
555 		return (DCMD_ERR);
556 	}
557 
558 	if (mask != 0 && !(sq.sq_flags & mask))
559 		return (DCMD_OK);
560 
561 	if (not_mask != 0 && (sq.sq_flags & not_mask))
562 		return (DCMD_OK);
563 
564 	sqtype = (sq.sq_type >> 8) & 0xff;
565 
566 	if (tmask != 0 && !(sqtype & tmask))
567 		return (DCMD_OK);
568 
569 	if (not_tmask != 0 && (sqtype & not_tmask))
570 		return (DCMD_OK);
571 
572 	/*
573 	 * Options are specified for filtering, so If any option is specified on
574 	 * the command line, just print address and exit.
575 	 */
576 	if (quiet) {
577 		mdb_printf("%0?p\n", addr);
578 		return (DCMD_OK);
579 	}
580 
581 	mdb_printf("%0?p %02x  %02x  %-3u %-3u %0?p  %1x %-3d\n",
582 	    addr, sq.sq_flags & 0xff, sqtype, sq.sq_count,
583 	    sq.sq_nqueues, sq.sq_outer, sq.sq_svcflags, sq.sq_pri);
584 
585 	if (verbose) {
586 		int i, arm = 0;
587 
588 		for (i = 0; sqf[i].strf_name != NULL; i++) {
589 			if (!(sq.sq_flags & (1 << i)))
590 				continue;
591 			if (!arm) {
592 				mdb_printf("%*s|\n%*s+-->  ",
593 				    SYNC_FLGDELT, "", SYNC_FLGDELT, "");
594 				arm = 1;
595 			} else
596 				mdb_printf("%*s      ", SYNC_FLGDELT, "");
597 
598 			mdb_printf("%-12s %s\n",
599 			    sqf[i].strf_name, sqf[i].strf_descr);
600 		}
601 
602 		for (i = 0; sqt[i].strf_name != NULL; i++) {
603 			if (!(sqtype & (1 << i)))
604 				continue;
605 			if (!arm) {
606 				mdb_printf("%*s|\n%*s+-->  ",
607 				    SYNC_TYPDELT, "", SYNC_TYPDELT, "");
608 				arm = 1;
609 			} else
610 				mdb_printf("%*s      ", SYNC_TYPDELT, "");
611 
612 			mdb_printf("%-12s %s\n",
613 			    sqt[i].strf_name, sqt[i].strf_descr);
614 		}
615 	}
616 
617 	return (DCMD_OK);
618 }
619 
620 int
621 stdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
622 {
623 	const int STREAM_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 10);
624 
625 	stdata_t  sd;
626 
627 	const char *flag = NULL, *not_flag = NULL;
628 	uint_t verbose = FALSE;
629 	uint_t quiet = FALSE;
630 	uint32_t mask = 0, not_mask = 0;
631 
632 	if (!(flags & DCMD_ADDRSPEC)) {
633 		if (mdb_walk_dcmd("genunix`stream_head_cache",
634 		    "genunix`stdata", argc, argv) == -1) {
635 			mdb_warn("failed to walk stream head cache");
636 			return (DCMD_ERR);
637 		}
638 		return (DCMD_OK);
639 	}
640 
641 	if (flags & DCMD_PIPE_OUT)
642 		quiet = TRUE;
643 
644 	if (mdb_getopts(argc, argv,
645 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
646 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
647 	    'f', MDB_OPT_STR, &flag,
648 	    'F', MDB_OPT_STR, &not_flag,
649 	    NULL) != argc)
650 		return (DCMD_USAGE);
651 
652 	/*
653 	 * If any of the filtering flags is specified, don't print anything
654 	 * except the matching pointer.
655 	 */
656 	if (flag != NULL || not_flag != NULL)
657 		quiet = TRUE;
658 
659 	if (DCMD_HDRSPEC(flags) && !quiet) {
660 		mdb_printf("%?s %?s %8s %?s %s %s\n",
661 		    "ADDR", "WRQ", "FLAGS", "VNODE", "N/A", "REF");
662 	}
663 
664 	if (flag != NULL && streams_parse_flag(stdf, flag, &mask) == -1) {
665 		mdb_warn("unrecognized stream flag '%s'\n", flag);
666 		streams_flag_usage(stdf);
667 		return (DCMD_USAGE);
668 	}
669 
670 	if (not_flag != NULL &&
671 	    streams_parse_flag(stdf, not_flag, &not_mask) == -1) {
672 		mdb_warn("unrecognized stream flag '%s'\n", flag);
673 		streams_flag_usage(stdf);
674 		return (DCMD_USAGE);
675 	}
676 
677 	if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
678 		mdb_warn("couldn't read stdata at %p", addr);
679 		return (DCMD_ERR);
680 	}
681 
682 	/*
683 	 * If stream doesn't pass filtering criteria, don't print anything and
684 	 * just return.
685 	 */
686 
687 	if (mask != 0 && !(sd.sd_flag & mask))
688 		return (DCMD_OK);
689 
690 	if (not_mask != 0 && (sd.sd_flag & not_mask))
691 		return (DCMD_OK);
692 
693 	/*
694 	 * Options are specified for filtering, so If any option is specified on
695 	 * the command line, just print address and exit.
696 	 */
697 	if (quiet) {
698 		mdb_printf("%0?p\n", addr);
699 		return (DCMD_OK);
700 	}
701 
702 	mdb_printf("%0?p %0?p %08x %0?p %d/%d %d\n",
703 	    addr, sd.sd_wrq, sd.sd_flag, sd.sd_vnode,
704 	    sd.sd_pushcnt, sd.sd_anchor, sd.sd_refcnt);
705 
706 	if (verbose) {
707 		int i, arm = 0;
708 
709 		for (i = 0; stdf[i].strf_name != NULL; i++) {
710 			if (!(sd.sd_flag & (1 << i)))
711 				continue;
712 			if (!arm) {
713 				mdb_printf("%*s|\n%*s+-->  ",
714 				    STREAM_FLGDELT, "", STREAM_FLGDELT, "");
715 				arm = 1;
716 			} else
717 				mdb_printf("%*s      ", STREAM_FLGDELT, "");
718 
719 			mdb_printf("%-12s %s\n",
720 			    stdf[i].strf_name, stdf[i].strf_descr);
721 		}
722 	}
723 
724 	return (DCMD_OK);
725 }
726 
727 /*ARGSUSED*/
728 static void
729 qprint_syncq(queue_t *addr, queue_t *q)
730 {
731 	mdb_printf("%p\n", q->q_syncq);
732 }
733 
734 /*ARGSUSED*/
735 static void
736 qprint_stream(queue_t *addr, queue_t *q)
737 {
738 	mdb_printf("%p\n", q->q_stream);
739 }
740 
741 static void
742 qprint_wrq(queue_t *addr, queue_t *q)
743 {
744 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)));
745 }
746 
747 static void
748 qprint_rdq(queue_t *addr, queue_t *q)
749 {
750 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr): (addr)-1));
751 }
752 
753 static void
754 qprint_otherq(queue_t *addr, queue_t *q)
755 {
756 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)-1));
757 }
758 
759 static int
760 q2x(uintptr_t addr, int argc, qprint_func prfunc)
761 {
762 	queue_t q;
763 
764 	if (argc != 0)
765 		return (DCMD_USAGE);
766 
767 	if (mdb_vread(&q, sizeof (q), addr) == -1) {
768 		mdb_warn("couldn't read queue at %p", addr);
769 		return (DCMD_ERR);
770 	}
771 
772 	prfunc((queue_t *)addr, &q);
773 
774 	return (DCMD_OK);
775 }
776 
777 /*ARGSUSED*/
778 int
779 q2syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
780 {
781 	return (q2x(addr, argc, qprint_syncq));
782 }
783 
784 /*ARGSUSED*/
785 int
786 q2stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
787 {
788 	return (q2x(addr, argc, qprint_stream));
789 }
790 
791 /*ARGSUSED*/
792 int
793 q2rdq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
794 {
795 	return (q2x(addr, argc, qprint_rdq));
796 }
797 
798 /*ARGSUSED*/
799 int
800 q2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
801 {
802 	return (q2x(addr, argc, qprint_wrq));
803 }
804 
805 /*ARGSUSED*/
806 int
807 q2otherq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
808 {
809 	return (q2x(addr, argc, qprint_otherq));
810 }
811 
812 static int
813 sd2x(uintptr_t addr, int argc, sdprint_func prfunc)
814 {
815 	stdata_t sd;
816 
817 	if (argc != 0)
818 		return (DCMD_USAGE);
819 
820 	if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
821 		mdb_warn("couldn't read stream head at %p", addr);
822 		return (DCMD_ERR);
823 	}
824 
825 	prfunc((stdata_t *)addr, &sd);
826 
827 	return (DCMD_OK);
828 }
829 
830 /*ARGSUSED*/
831 static void
832 sdprint_wrq(stdata_t *addr, stdata_t *sd)
833 {
834 	mdb_printf("%p\n", sd->sd_wrq);
835 }
836 
837 static void
838 sdprint_mate(stdata_t *addr, stdata_t *sd)
839 {
840 	mdb_printf("%p\n", sd->sd_mate ? sd->sd_mate : addr);
841 }
842 
843 /*ARGSUSED*/
844 int
845 str2mate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
846 {
847 	return (sd2x(addr, argc, sdprint_mate));
848 }
849 
850 /*ARGSUSED*/
851 int
852 str2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
853 {
854 	return (sd2x(addr, argc, sdprint_wrq));
855 }
856 
857 /*
858  * If this syncq is a part of the queue pair structure, find the queue for it.
859  */
860 /*ARGSUSED*/
861 int
862 syncq2q(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
863 {
864 	syncq_t sq;
865 	queue_t q;
866 	queue_t *qp;
867 
868 	if (argc != 0)
869 		return (DCMD_USAGE);
870 
871 	if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
872 		mdb_warn("couldn't read syncq at %p", addr);
873 		return (DCMD_ERR);
874 	}
875 
876 	/* Try to find its queue */
877 	qp = (queue_t *)addr - 2;
878 
879 	if ((mdb_vread(&q, sizeof (q), (uintptr_t)qp) == -1) ||
880 	    (q.q_syncq != (syncq_t *)addr)) {
881 		mdb_warn("syncq2q: %p is not part of any queue\n", addr);
882 		return (DCMD_ERR);
883 	} else
884 		mdb_printf("%p\n", qp);
885 
886 	return (DCMD_OK);
887 }
888 
889 int
890 queue_walk_init(mdb_walk_state_t *wsp)
891 {
892 	if (wsp->walk_addr == NULL &&
893 	    mdb_readvar(&wsp->walk_addr, "qhead") == -1) {
894 		mdb_warn("failed to read 'qhead'");
895 		return (WALK_ERR);
896 	}
897 
898 	wsp->walk_data = mdb_alloc(sizeof (queue_t), UM_SLEEP);
899 	return (WALK_NEXT);
900 }
901 
902 int
903 queue_link_step(mdb_walk_state_t *wsp)
904 {
905 	int status;
906 
907 	if (wsp->walk_addr == NULL)
908 		return (WALK_DONE);
909 
910 	if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
911 		mdb_warn("failed to read queue at %p", wsp->walk_addr);
912 		return (WALK_DONE);
913 	}
914 
915 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
916 	    wsp->walk_cbdata);
917 
918 	wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_link);
919 	return (status);
920 }
921 
922 int
923 queue_next_step(mdb_walk_state_t *wsp)
924 {
925 	int status;
926 
927 	if (wsp->walk_addr == NULL)
928 		return (WALK_DONE);
929 
930 	if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
931 		mdb_warn("failed to read queue at %p", wsp->walk_addr);
932 		return (WALK_DONE);
933 	}
934 
935 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
936 	    wsp->walk_cbdata);
937 
938 	wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_next);
939 	return (status);
940 }
941 
942 void
943 queue_walk_fini(mdb_walk_state_t *wsp)
944 {
945 	mdb_free(wsp->walk_data, sizeof (queue_t));
946 }
947 
948 int
949 str_walk_init(mdb_walk_state_t *wsp)
950 {
951 	stdata_t s;
952 
953 	if (wsp->walk_addr == NULL) {
954 		mdb_warn("walk must begin at address of stdata_t\n");
955 		return (WALK_ERR);
956 	}
957 
958 	if (mdb_vread(&s, sizeof (s), wsp->walk_addr) == -1) {
959 		mdb_warn("failed to read stdata at %p", wsp->walk_addr);
960 		return (WALK_ERR);
961 	}
962 
963 	wsp->walk_addr = (uintptr_t)s.sd_wrq;
964 	wsp->walk_data = mdb_alloc(sizeof (queue_t) * 2, UM_SLEEP);
965 
966 	return (WALK_NEXT);
967 }
968 
969 int
970 strr_walk_step(mdb_walk_state_t *wsp)
971 {
972 	queue_t *rq = wsp->walk_data, *wq = rq + 1;
973 	int status;
974 
975 	if (wsp->walk_addr == NULL)
976 		return (WALK_DONE);
977 
978 	if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
979 	    wsp->walk_addr - sizeof (queue_t)) == -1) {
980 		mdb_warn("failed to read queue pair at %p",
981 		    wsp->walk_addr - sizeof (queue_t));
982 		return (WALK_DONE);
983 	}
984 
985 	status = wsp->walk_callback(wsp->walk_addr - sizeof (queue_t),
986 	    rq, wsp->walk_cbdata);
987 
988 	if (wq->q_next != NULL)
989 		wsp->walk_addr = (uintptr_t)wq->q_next;
990 	else
991 		wsp->walk_addr = mdb_qwnext(wq);
992 
993 	return (status);
994 }
995 
996 int
997 strw_walk_step(mdb_walk_state_t *wsp)
998 {
999 	queue_t *rq = wsp->walk_data, *wq = rq + 1;
1000 	int status;
1001 
1002 	if (wsp->walk_addr == NULL)
1003 		return (WALK_DONE);
1004 
1005 	if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
1006 	    wsp->walk_addr - sizeof (queue_t)) == -1) {
1007 		mdb_warn("failed to read queue pair at %p",
1008 		    wsp->walk_addr - sizeof (queue_t));
1009 		return (WALK_DONE);
1010 	}
1011 
1012 	status = wsp->walk_callback(wsp->walk_addr, wq, wsp->walk_cbdata);
1013 
1014 	if (wq->q_next != NULL)
1015 		wsp->walk_addr = (uintptr_t)wq->q_next;
1016 	else
1017 		wsp->walk_addr = mdb_qwnext(wq);
1018 
1019 	return (status);
1020 }
1021 
1022 void
1023 str_walk_fini(mdb_walk_state_t *wsp)
1024 {
1025 	mdb_free(wsp->walk_data, sizeof (queue_t) * 2);
1026 }
1027 
1028 static int
1029 print_qpair(uintptr_t addr, const queue_t *q, uint_t *depth)
1030 {
1031 	static const char box_lid[] =
1032 	    "+-----------------------+-----------------------+\n";
1033 	static const char box_sep[] =
1034 	    "|                       |                       |\n";
1035 
1036 	char wname[32], rname[32], info1[256], *info2;
1037 
1038 	if (*depth != 0) {
1039 		mdb_printf("            |                       ^\n");
1040 		mdb_printf("            v                       |\n");
1041 	} else
1042 		mdb_printf("\n");
1043 
1044 	(void) mdb_qname(_WR(q), wname, sizeof (wname));
1045 	(void) mdb_qname(_RD(q), rname, sizeof (rname));
1046 
1047 	mdb_qinfo(_WR(q), info1, sizeof (info1));
1048 	if ((info2 = strchr(info1, '\n')) != NULL)
1049 		*info2++ = '\0';
1050 	else
1051 		info2 = "";
1052 
1053 	mdb_printf(box_lid);
1054 	mdb_printf("| 0x%-19p | 0x%-19p | %s\n",
1055 	    addr, addr - sizeof (queue_t), info1);
1056 
1057 	mdb_printf("| %<b>%-21s%</b> | %<b>%-21s%</b> |", wname, rname);
1058 	mdb_flush(); /* Account for buffered terminal sequences */
1059 
1060 	mdb_printf(" %s\n", info2);
1061 	mdb_printf(box_sep);
1062 
1063 	mdb_qinfo(_RD(q), info1, sizeof (info1));
1064 	if ((info2 = strchr(info1, '\n')) != NULL)
1065 		*info2++ = '\0';
1066 	else
1067 		info2 = "";
1068 
1069 	mdb_printf("| cnt = 0t%-13lu | cnt = 0t%-13lu | %s\n",
1070 	    _WR(q)->q_count, _RD(q)->q_count, info1);
1071 
1072 	mdb_printf("| flg = 0x%08x      | flg = 0x%08x      | %s\n",
1073 	    _WR(q)->q_flag, _RD(q)->q_flag, info2);
1074 
1075 	mdb_printf(box_lid);
1076 	*depth += 1;
1077 	return (0);
1078 }
1079 
1080 /*ARGSUSED*/
1081 int
1082 stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1083 {
1084 	uint_t d = 0;	/* Depth counter for print_qpair */
1085 
1086 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
1087 		return (DCMD_USAGE);
1088 
1089 	if (mdb_pwalk("writeq", (mdb_walk_cb_t)print_qpair, &d, addr) == -1) {
1090 		mdb_warn("failed to walk writeq");
1091 		return (DCMD_ERR);
1092 	}
1093 
1094 	return (DCMD_OK);
1095 }
1096 
1097 int
1098 mblk_walk_init(mdb_walk_state_t *wsp)
1099 {
1100 	wsp->walk_data = mdb_alloc(sizeof (mblk_t), UM_SLEEP);
1101 	return (WALK_NEXT);
1102 }
1103 
1104 int
1105 b_cont_step(mdb_walk_state_t *wsp)
1106 {
1107 	int status;
1108 
1109 	if (wsp->walk_addr == NULL)
1110 		return (WALK_DONE);
1111 
1112 	if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
1113 		mdb_warn("failed to read mblk at %p", wsp->walk_addr);
1114 		return (WALK_DONE);
1115 	}
1116 
1117 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1118 	    wsp->walk_cbdata);
1119 
1120 	wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_cont);
1121 	return (status);
1122 }
1123 
1124 int
1125 b_next_step(mdb_walk_state_t *wsp)
1126 {
1127 	int status;
1128 
1129 	if (wsp->walk_addr == NULL)
1130 		return (WALK_DONE);
1131 
1132 	if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
1133 		mdb_warn("failed to read mblk at %p", wsp->walk_addr);
1134 		return (WALK_DONE);
1135 	}
1136 
1137 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1138 	    wsp->walk_cbdata);
1139 
1140 	wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_next);
1141 	return (status);
1142 }
1143 
1144 void
1145 mblk_walk_fini(mdb_walk_state_t *wsp)
1146 {
1147 	mdb_free(wsp->walk_data, sizeof (mblk_t));
1148 }
1149 
1150 /* ARGSUSED */
1151 int
1152 mblk2dblk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1153 {
1154 	mblk_t mb;
1155 
1156 	if (argc != 0)
1157 		return (DCMD_USAGE);
1158 
1159 	if (mdb_vread(&mb, sizeof (mb), addr) == -1) {
1160 		mdb_warn("couldn't read mblk at %p", addr);
1161 		return (DCMD_ERR);
1162 	}
1163 
1164 	mdb_printf("%p\n", mb.b_datap);
1165 	return (DCMD_OK);
1166 }
1167 
1168 static void
1169 mblk_error(int *error, uintptr_t addr, char *message)
1170 {
1171 	if (!*error)
1172 		mdb_printf("%?lx: ", addr);
1173 	else
1174 		mdb_printf(", ");
1175 	mdb_printf("%s", message);
1176 	*error = 1;
1177 }
1178 
1179 int
1180 mblk_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1181 {
1182 	mblk_t	mb;
1183 	dblk_t	db;
1184 	int	error = 0;
1185 
1186 	if (!(flags & DCMD_ADDRSPEC)) {
1187 		if (mdb_walk_dcmd("streams_mblk", "mblk_verify", argc, argv) ==
1188 		    -1) {
1189 			mdb_warn("can't walk mblk cache");
1190 			return (DCMD_ERR);
1191 		}
1192 		return (DCMD_OK);
1193 	}
1194 
1195 	if (mdb_vread(&mb, sizeof (mblk_t), addr) == -1) {
1196 		mdb_warn("can't read mblk_t at 0x%lx", addr);
1197 		return (DCMD_ERR);
1198 	}
1199 
1200 	if (mdb_vread(&db, sizeof (dblk_t), (uintptr_t)mb.b_datap) == -1) {
1201 		mdb_warn("%?lx: invalid b_datap pointer\n", addr);
1202 		return (DCMD_ERR);
1203 	}
1204 
1205 	if (mb.b_rptr < db.db_base || mb.b_rptr > db.db_lim)
1206 		mblk_error(&error, addr, "b_rptr out of range");
1207 
1208 	if (mb.b_wptr < db.db_base || mb.b_wptr > db.db_lim)
1209 		mblk_error(&error, addr, "b_wptr out of range");
1210 
1211 	if (error)
1212 		mdb_printf("\n");
1213 
1214 	return (error ? DCMD_ERR : DCMD_OK);
1215 }
1216 
1217 int
1218 mblk_prt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1219 {
1220 	const int MBLK_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
1221 	mblk_t mblk;
1222 	dblk_t dblk;
1223 	int b_flag;
1224 	int db_type;
1225 	int mblklen;
1226 	uint64_t len = ~0UL;
1227 	uint64_t glen = ~0UL;
1228 	uint64_t llen = ~0UL;
1229 	uint64_t blen = ~0UL;
1230 	const char *dbtype;
1231 	const char *flag = NULL, *not_flag = NULL;
1232 	const char *typ = NULL, *not_typ = NULL;
1233 	uintptr_t  dbaddr = 0;
1234 	uint32_t tmask = 0, not_tmask = 0;
1235 	uint32_t mask = 0, not_mask = 0;
1236 	uint_t quiet = FALSE;
1237 	uint_t verbose = FALSE;
1238 
1239 	if (!(flags & DCMD_ADDRSPEC)) {
1240 		if (mdb_walk_dcmd("genunix`streams_mblk", "genunix`mblk",
1241 		    argc, argv) == -1) {
1242 			mdb_warn("failed to walk mblk cache");
1243 			return (DCMD_ERR);
1244 		}
1245 		return (DCMD_OK);
1246 	}
1247 
1248 	if (flags & DCMD_PIPE_OUT)
1249 		quiet = TRUE;
1250 
1251 	if (mdb_getopts(argc, argv,
1252 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
1253 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
1254 	    'f', MDB_OPT_STR, &flag,
1255 	    'F', MDB_OPT_STR, &not_flag,
1256 	    't', MDB_OPT_STR, &typ,
1257 	    'T', MDB_OPT_STR, &not_typ,
1258 	    'l', MDB_OPT_UINT64, &len,
1259 	    'L', MDB_OPT_UINT64, &llen,
1260 	    'G', MDB_OPT_UINT64, &glen,
1261 	    'b', MDB_OPT_UINT64, &blen,
1262 	    'd', MDB_OPT_UINTPTR, &dbaddr,
1263 	    NULL) != argc)
1264 		return (DCMD_USAGE);
1265 
1266 	/*
1267 	 * If any of the filtering flags is specified, don't print anything
1268 	 * except the matching pointer.
1269 	 */
1270 	if ((flag != NULL) || (not_flag != NULL) || (typ != NULL) ||
1271 	    (not_typ != NULL) || (len != ~0UL) || (glen != ~0UL) ||
1272 	    (llen != ~0UL) || (blen != ~0UL) || (dbaddr != 0))
1273 		quiet = TRUE;
1274 
1275 	if (flag != NULL && streams_parse_flag(mbf, flag, &mask) == -1) {
1276 		mdb_warn("unrecognized mblk flag '%s'\n", flag);
1277 		streams_flag_usage(mbf);
1278 		return (DCMD_USAGE);
1279 	}
1280 
1281 	if (not_flag != NULL &&
1282 	    streams_parse_flag(mbf, not_flag, &not_mask) == -1) {
1283 		mdb_warn("unrecognized mblk flag '%s'\n", flag);
1284 		streams_flag_usage(mbf);
1285 		return (DCMD_USAGE);
1286 	}
1287 
1288 	if (typ != NULL && streams_parse_type(mbt, typ, &tmask) == -1) {
1289 		mdb_warn("unrecognized dblk type '%s'\n", typ);
1290 		streams_type_usage(mbt);
1291 		return (DCMD_USAGE);
1292 	}
1293 
1294 	if (not_typ != NULL && streams_parse_type(mbt, not_typ, &not_tmask)
1295 	    == -1) {
1296 		mdb_warn("unrecognized dblk type '%s'\n", not_typ);
1297 		streams_type_usage(mbt);
1298 		return (DCMD_USAGE);
1299 	}
1300 
1301 	if (DCMD_HDRSPEC(flags) && !quiet) {
1302 		mdb_printf("%?s %2s %-7s %-5s %-5s %?s %?s\n",
1303 		    "ADDR", "FL", "TYPE", "LEN", "BLEN", "RPTR", "DBLK");
1304 	}
1305 
1306 	if (mdb_vread(&mblk, sizeof (mblk), addr) == -1) {
1307 		mdb_warn("couldn't read mblk at %p", addr);
1308 		return (DCMD_ERR);
1309 	}
1310 	b_flag = mblk.b_flag;
1311 
1312 	if (mask != 0 && !(b_flag & mask))
1313 		return (DCMD_OK);
1314 
1315 	if (not_mask != 0 && (b_flag & not_mask))
1316 		return (DCMD_OK);
1317 
1318 	if (mdb_vread(&dblk, sizeof (dblk), (uintptr_t)(mblk.b_datap)) == -1) {
1319 		mdb_warn("couldn't read dblk at %p/%p", addr, mblk.b_datap);
1320 		return (DCMD_ERR);
1321 	}
1322 	db_type = dblk.db_type;
1323 
1324 	/* M_DATA is 0, so tmask has special value 0xff for it */
1325 	if (tmask != 0) {
1326 		if ((tmask == M_DATA_T && db_type != M_DATA) ||
1327 		    (tmask != M_DATA_T && db_type != tmask))
1328 			return (DCMD_OK);
1329 	}
1330 
1331 	if (not_tmask != 0) {
1332 		if ((not_tmask == M_DATA_T && db_type == M_DATA) ||
1333 		    (db_type == not_tmask))
1334 			return (DCMD_OK);
1335 	}
1336 
1337 	if (dbaddr != 0 && (uintptr_t)mblk.b_datap != dbaddr)
1338 		return (DCMD_OK);
1339 
1340 	mblklen = MBLKL(&mblk);
1341 
1342 	if ((len != ~0UL) && (len != mblklen))
1343 		return (DCMD_OK);
1344 
1345 	if ((llen != ~0Ul) && (mblklen > (int)llen))
1346 		return (DCMD_OK);
1347 
1348 	if ((glen != ~0Ul) && (mblklen < (int)glen))
1349 		return (DCMD_OK);
1350 
1351 	if ((blen != ~0UL) && (blen != (dblk.db_lim - dblk.db_base)))
1352 		return (DCMD_OK);
1353 
1354 	/*
1355 	 * Options are specified for filtering, so If any option is specified on
1356 	 * the command line, just print address and exit.
1357 	 */
1358 	if (quiet) {
1359 		mdb_printf("%0?p\n", addr);
1360 		return (DCMD_OK);
1361 	}
1362 
1363 	/* Figure out symbolic DB_TYPE */
1364 	if (db_type < A_SIZE(db_control_types)) {
1365 		dbtype = db_control_types[db_type];
1366 	} else {
1367 		/*
1368 		 * Must be a high-priority message -- adjust so that
1369 		 * "QPCTL + 1" corresponds to db_control_hipri_types[0]
1370 		 */
1371 		db_type -= (QPCTL + 1);
1372 		if (db_type >= 0 && db_type < A_SIZE(db_control_hipri_types))
1373 			dbtype = db_control_hipri_types[db_type];
1374 		else
1375 			dbtype = "UNKNOWN";
1376 	}
1377 
1378 	mdb_printf("%0?p %-2x %-7s %-5d %-5d %0?p %0?p\n",
1379 	    addr, b_flag, dbtype, mblklen, dblk.db_lim - dblk.db_base,
1380 	    mblk.b_rptr, mblk.b_datap);
1381 
1382 	if (verbose) {
1383 		int i, arm = 0;
1384 
1385 		for (i = 0; mbf[i].strf_name != NULL; i++) {
1386 			if (!(b_flag & (1 << i)))
1387 				continue;
1388 			if (!arm) {
1389 				mdb_printf("%*s|\n%*s+-->  ",
1390 				    MBLK_FLGDELT, "", MBLK_FLGDELT, "");
1391 				arm = 1;
1392 			} else
1393 				mdb_printf("%*s      ", MBLK_FLGDELT, "");
1394 
1395 			mdb_printf("%-12s %s\n",
1396 			    mbf[i].strf_name, mbf[i].strf_descr);
1397 		}
1398 	}
1399 	return (DCMD_OK);
1400 }
1401 
1402 /*
1403  * Streams flow trace walkers.
1404  */
1405 
1406 int
1407 strftblk_walk_init(mdb_walk_state_t *wsp)
1408 {
1409 	ftblkdata_t *ftd;
1410 	dblk_t	db;
1411 
1412 	/* Get the dblock from the address */
1413 	if (mdb_vread(&db, sizeof (dblk_t), wsp->walk_addr) == -1) {
1414 		mdb_warn("failed to read dblk at %p", wsp->walk_addr);
1415 		return (WALK_ERR);
1416 	}
1417 
1418 	/* Is there any flow trace data? */
1419 	if (db.db_fthdr == NULL) {
1420 		return (WALK_DONE);
1421 	}
1422 
1423 	wsp->walk_addr = (uintptr_t)((char *)db.db_fthdr +
1424 	    offsetof(fthdr_t, first));
1425 
1426 	ftd = mdb_alloc(sizeof (ftblkdata_t), UM_SLEEP);
1427 	ftd->ft_ix = 0;
1428 	ftd->ft_in_evlist = B_FALSE;
1429 	wsp->walk_data = ftd;
1430 
1431 	return (WALK_NEXT);
1432 }
1433 
1434 int
1435 strftblk_step(mdb_walk_state_t *wsp)
1436 {
1437 	ftblkdata_t *ftd;
1438 	ftblk_t *ftbp;
1439 	int status = WALK_NEXT;
1440 
1441 	if (wsp->walk_addr == NULL)
1442 		return (WALK_DONE);
1443 
1444 	ftd = (ftblkdata_t *)wsp->walk_data;
1445 	ftbp = &(ftd->ft_data);
1446 
1447 	if (! ftd->ft_in_evlist) {
1448 		/* Read a new ft block */
1449 		if (mdb_vread(ftbp, sizeof (ftblk_t),
1450 		    wsp->walk_addr) == -1) {
1451 			mdb_warn("failed to read ftblk at %p", wsp->walk_addr);
1452 			return (WALK_ERR);
1453 		}
1454 		/*
1455 		 * Check correctness of the index field.
1456 		 */
1457 		if (ftbp->ix < 0 || ftbp->ix > FTBLK_EVNTS) {
1458 			mdb_warn("ftblk: incorrect index value %i\n", ftbp->ix);
1459 			return (WALK_ERR);
1460 		}
1461 		ftd->ft_ix = 1;
1462 		ftd->ft_in_evlist = B_TRUE;
1463 	}
1464 
1465 	if (ftd->ft_ix > ftbp->ix) {
1466 		ftd->ft_in_evlist = B_FALSE;
1467 		/* End of event list reached - move to the next event block */
1468 		wsp->walk_addr = (uintptr_t)ftbp->nxt;
1469 	} else {
1470 		/* Print event address */
1471 		status = wsp->walk_callback((uintptr_t)((char *)wsp->walk_addr +
1472 		    offsetof(ftblk_t, ev) +
1473 		    (ftd->ft_ix - 1) * sizeof (struct ftevnt)),
1474 		    wsp->walk_data, wsp->walk_cbdata);
1475 		ftd->ft_ix++;
1476 	}
1477 
1478 	return (status);
1479 }
1480 
1481 void
1482 strftblk_walk_fini(mdb_walk_state_t *wsp)
1483 {
1484 	mdb_free(wsp->walk_data, sizeof (ftblkdata_t));
1485 }
1486 
1487 static const char *
1488 getqname(const void *nameptr, char *buf, uint_t bufsize)
1489 {
1490 	char *cp;
1491 
1492 	if (mdb_readstr(buf, bufsize, (uintptr_t)nameptr) == -1)
1493 		goto fail;
1494 
1495 	/*
1496 	 * Sanity-check the name we read.  This is needed because the pointer
1497 	 * value may have been recycled for some other purpose in the kernel
1498 	 * (e.g., if the STREAMS module was unloaded).
1499 	 */
1500 	for (cp = buf; *cp != '\0'; cp++) {
1501 		if (!isprint(*cp))
1502 			goto fail;
1503 	}
1504 	return (buf);
1505 fail:
1506 	return (strncpy(buf, "?", bufsize));
1507 }
1508 
1509 /*ARGSUSED*/
1510 int
1511 strftevent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1512 {
1513 	int i;
1514 	struct ftstk stk;
1515 	struct ftevnt ev;
1516 	char name[FMNAMESZ + 1];
1517 	boolean_t havestk = B_FALSE;
1518 
1519 	if (!(flags & DCMD_ADDRSPEC))
1520 		return (DCMD_USAGE);
1521 
1522 	if (DCMD_HDRSPEC(flags)) {
1523 		mdb_printf("%?s %-18s %-9s %-18s %4s %s\n",
1524 		    "ADDR", "Q/CALLER", "QNEXT", "STACK", "DATA", "EVENT");
1525 	}
1526 
1527 	if (mdb_vread(&ev, sizeof (ev), addr) == -1) {
1528 		mdb_warn("couldn't read struct ftevnt at %p", addr);
1529 		return (DCMD_ERR);
1530 	}
1531 
1532 	mdb_printf("%0?p", addr);
1533 
1534 	if (ev.evnt & FTEV_QMASK)
1535 		mdb_printf(" %-18s", getqname(ev.mid, name, sizeof (name)));
1536 	else
1537 		mdb_printf(" %-18a", ev.mid);
1538 
1539 	if ((ev.evnt & FTEV_MASK) == FTEV_PUTNEXT)
1540 		mdb_printf(" %-9s", getqname(ev.midnext, name, sizeof (name)));
1541 	else
1542 		mdb_printf(" %-9s", "--");
1543 
1544 	if (ev.stk == NULL) {
1545 		mdb_printf(" %-18s", "--");
1546 	} else if (mdb_vread(&stk, sizeof (stk), (uintptr_t)ev.stk) == -1) {
1547 		mdb_printf(" %-18s", "?");
1548 	} else {
1549 		mdb_printf(" %-18a", stk.fs_stk[0]);
1550 		havestk = B_TRUE;
1551 	}
1552 
1553 	mdb_printf(" %4x", ev.data);
1554 	ft_printevent(ev.evnt);
1555 	mdb_printf("\n");
1556 
1557 	if (havestk) {
1558 		for (i = 1; i < stk.fs_depth; i++) {
1559 			mdb_printf("%?s %-18s %-9s %-18a\n", "", "", "",
1560 			    stk.fs_stk[i]);
1561 		}
1562 	}
1563 
1564 	return (DCMD_OK);
1565 }
1566 
1567 static void
1568 ft_printevent(ushort_t ev)
1569 {
1570 	ushort_t proc_ev = (ev & (FTEV_PROC_START | 0xFF)) - FTEV_PROC_START;
1571 	ushort_t alloc_ev = ev & FTEV_CALLER;
1572 
1573 	/* Get event class first */
1574 	if (ev & FTEV_PROC_START) {
1575 		if (proc_ev >= A_SIZE(ftev_proc))
1576 			mdb_printf(" undefined");
1577 		else
1578 			mdb_printf(" %s", ftev_proc[proc_ev]);
1579 	} else if (alloc_ev >= A_SIZE(ftev_alloc)) {
1580 		mdb_printf(" undefined");
1581 	} else {
1582 		mdb_printf(" %s", ftev_alloc[alloc_ev]);
1583 	}
1584 
1585 	/* Print event modifiers, if any */
1586 	if (ev & (FTEV_PS | FTEV_CS | FTEV_ISWR)) {
1587 		mdb_printf("|");
1588 		if (ev & FTEV_ISWR)
1589 			mdb_printf("W");
1590 		if (ev & FTEV_CS)
1591 			mdb_printf("C");
1592 		if (ev & FTEV_PS)
1593 			mdb_printf("P");
1594 	}
1595 }
1596 
1597 /*
1598  * Help functions for STREAMS debugging facilities.
1599  */
1600 void
1601 queue_help(void)
1602 {
1603 	mdb_printf("Print queue information for a given queue pointer.\n"
1604 	    "\nWithout the address of a \"queue_t\" structure given, print "
1605 	    "information about all\n"
1606 	    "queues in the \"queue_cache\".\n\n"
1607 	    "Options:\n"
1608 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1609 	    "	-q:\t\tbe quiet - print queue pointer only\n"
1610 	    "	-f flag:\tprint only queues with flag set\n"
1611 	    "	-F flag:\tprint only queues with flag NOT set\n"
1612 	    "	-m modname:\tprint only queues with specified module name\n"
1613 	    "	-s syncq_addr:\tprint only queues which use specified syncq\n\n"
1614 	    "Available conversions:\n"
1615 	    "	q2rdq:		given a queue addr print read queue pointer\n"
1616 	    "	q2wrq:		given a queue addr print write queue pointer\n"
1617 	    "	q2otherq:	given a queue addr print other queue pointer\n"
1618 	    "	q2syncq:	given a queue addr print syncq pointer"
1619 	    " (::help syncq)\n"
1620 	    "	q2stream:	given a queue addr print its stream pointer\n"
1621 	    "\t\t(see ::help stream and ::help stdata)\n\n"
1622 	    "To walk q_next pointer of the queue use\n"
1623 	    "	queue_addr::walk qnext\n");
1624 }
1625 
1626 void
1627 syncq_help(void)
1628 {
1629 	mdb_printf("Print syncq information for a given syncq pointer.\n"
1630 	    "\nWithout the address of a \"syncq_t\" structure given, print "
1631 	    "information about all\n"
1632 	    "syncqs in the \"syncq_cache\".\n\n"
1633 	    "Options:\n"
1634 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1635 	    "	-q:\t\tbe quiet - print syncq pointer only\n"
1636 	    "	-f flag:\tprint only syncqs with flag set\n"
1637 	    "	-F flag:\tprint only syncqs with flag NOT set\n"
1638 	    "	-t type:\tprint only syncqs with specified type\n"
1639 	    "	-T type:\tprint only syncqs with do NOT have specified type\n\n"
1640 	    "Available conversions:\n"
1641 	    "	syncq2q:\tgiven a syncq addr print queue address of the\n"
1642 	    "\t\t\tenclosing queue, if it is part of a queue\n\n"
1643 	    "See also: \"::help queue\" and \"::help stdata\"\n");
1644 }
1645 
1646 void
1647 stdata_help(void)
1648 {
1649 	mdb_printf("Print stdata information for a given stdata pointer.\n"
1650 	    "\nWithout the address of a \"stdata_t\" structure given, print "
1651 	    "information about all\n"
1652 	    "stream head pointers from the \"stream_head_cache\".\n\n"
1653 	    "Fields printed:\n"
1654 	    "	ADDR:\tstream head address\n"
1655 	    "	WRQ:\twrite queue pointer\n"
1656 	    "	FLAGS:\tstream head flags (use -v to show in symbolic form)\n"
1657 	    "	VNODE:\tstream vnode pointer\n"
1658 	    "	N/A:\tpushcount and anchor positions\n"
1659 	    "	REF:\tstream head reference counter\n\n"
1660 	    "Options:\n"
1661 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1662 	    "	-q:\t\tbe quiet - print stdata pointer only\n"
1663 	    "	-f flag:\tprint only stdatas with flag set\n"
1664 	    "	-F flag:\tprint only stdatas with flag NOT set\n\n"
1665 	    "Available conversions:\n"
1666 	    "	str2mate:\tgiven a stream head addr print its mate\n"
1667 	    "	str2wrq:\tgiven a stream head addr print its write queue\n\n"
1668 	    "See also: \"::help queue\" and \"::help syncq\"\n");
1669 }
1670 
1671 void
1672 mblk_help(void)
1673 {
1674 	mdb_printf("Print mblock information for a given mblk pointer.\n"
1675 	    "Without the address, print information about all mblocks.\n\n"
1676 	    "Fields printed:\n"
1677 	    "	ADDR:\tmblk address\n"
1678 	    "	FL:\tFlags\n"
1679 	    "	TYPE:\tType of corresponding dblock\n"
1680 	    "	LEN:\tData length as b_wptr - b_rptr\n"
1681 	    "	BLEN:\tDblock space as db_lim - db_base\n"
1682 	    "	RPTR:\tRead pointer\n"
1683 	    "	DBLK:\tDblock pointer\n\n"
1684 	    "Options:\n"
1685 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1686 	    "	-q:\t\tbe quiet - print mblk pointer only\n"
1687 	    "	-d dbaddr:\t\tprint mblks with specified dblk address\n"
1688 	    "	-f flag:\tprint only mblks with flag set\n"
1689 	    "	-F flag:\tprint only mblks with flag NOT set\n"
1690 	    "	-t type:\tprint only mblks of specified db_type\n"
1691 	    "	-T type:\tprint only mblks other then the specified db_type\n"
1692 	    "	-l len:\t\ttprint only mblks with MBLKL == len\n"
1693 	    "	-L len:\t\tprint only mblks with MBLKL <= len \n"
1694 	    "	-G len:\t\tprint only mblks with MBLKL >= len \n"
1695 	    "	-b len:\t\tprint only mblks with db_lim - db_base == len\n"
1696 	    "\n");
1697 }
1698