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